--------------------------
标题：5键键盘的输出 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
有一个特殊的5键键盘，上面有a，ctrl-c，ctrl-x，ctrl-v，ctrl-a五个键。a键在屏幕上输出一个字母a；ctrl-c将当前选择的字母复制到剪贴板；ctrl-x将当前选择的字母复制到剪贴板，并清空选择的字母；ctrl-v将当前剪贴板里的字母输出到屏幕；ctrl-a选择当前屏幕上的所有字母。

注意：
1 剪贴板初始为空，新的内容被复制到剪贴板时会覆盖原来的内容
2 当屏幕上没有字母时，ctrl-a无效
3 当没有选择字母时，ctrl-c和ctrl-x无效
4 当有字母被选择时，a和ctrl-v这两个有输出功能的键会先清空选择的字母，再进行输出
给定一系列键盘输入，输出最终屏幕上字母的数量。

输入描述:

输入为一行，为简化解析，用数字1 2 3 4 5代表a，ctrl-c，ctrl-x，ctrl-v，ctrl-a五个键的输入，数字用空格分隔

输出描述:

输出一个数字，为最终屏幕上字母的数量

示例1
输入：

1 1 1

输出：

3

说明：

连续键入3个a，故屏幕上字母的长度为3

示例2
输入：

1 1 5 1 5 2 4 4

输出：

2

说明：

输入两个a后ctrl-a选择这两个a，再输入a时选择的两个a先被清空，所以此时屏幕只有一个a，后续的ctrl-a，ctrl-c选择并复制了这一个a，最后两个ctrl-v在屏幕上输出两个a，故屏幕上字母的长度为2（第一个ctrl-v清空了屏幕上的那个a）

代码
//let s = readline().split(" ");
//let s = "1 1 1".split(" ");
let s = "1 1 5 1 5 2 4 4".split(" ");
 
let temp = "";//剪贴板
let screen = "";//屏幕
let select = "";//选择的
 
for(let i=0; i<s.length; i++){
 
    switch (s[i]){
        case "1":
            if(select!=""){
                screen = "a";
                select = "";
            }else {
                screen+="a";
            }
            break;
        case "2":
            if(select!=""){
                temp = select;
            }
            break;
        case "3":
            if(select!=""){
                temp = select;
                screen = "";
                select = "";
            }
            break;
        case "4":
            if(select!=""){
                screen = temp;
                select = "";
            }else {
                screen+=temp;
            }
            break;
        case "5":
            if(screen!=""){
                select = screen;
            }
            break;
    }
}
 
console.log(screen.length);

--------------------------
标题： IPv4地址 转换成整数 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
存在一种虚拟IPv4地址，由4小节组成，每节的范围为0~255，以#号间隔，虚拟IPv4地址可以转换为一个32位的整数，例如：

128#0#255#255，转换为32位整数的结果为2147549183（0x8000FFFF）

1#0#0#0，转换为32位整数的结果为16777216（0x01000000）

现以字符串形式给出一个虚拟IPv4地址，限制第1小节的范围为1~128，即每一节范围分别为(1~128)#(0~255)#(0~255)#(0~255)，要求每个IPv4地址只能对应到唯一的整数上。如果是非法IPv4，返回invalid IP

输入描述:

输入一行，虚拟IPv4地址格式字符串

输出描述:

输出以上，按照要求输出整型或者特定字符

1.示例1
输入

100#101#1#5

输出

1684340997

2.示例2
输入

1#2#3

输出

invalid IP

备注:
输入不能确保是合法的IPv4地址，需要对非法IPv4（空串，含有IP地址中不存在的字符，非合法的#分十进制，十进制整数不在合法区间内）进行识别，返回特定错误

代码
let strings = readLine().split("#");
//let strings = "100#101#1#5".split("#");
let len = strings.length;
let count = 0;
let isF = true;
 
if(len==4){
    for(let i=0;i<len;i++){
        let n = Number(strings[i]);
        if(i==0 && (n<1 || n>128)){ //第一节 1~128
            isF = false;
            break;
        }else if(n<0 || n>255){ //二、三、四节 0~255
            isF = false;
            break;
        }
        /**
         * 首先使用把IP地址分成4个数字： 128 199 231 44
         *
         * 把每个数字转换为2进制，如果转换后这个数字对应的二进制数不够8位，在左侧补0： 10000000 11000111 11100111 00101100
         */
        count += n<<(8*(3-i));
    }
}else {
    isF = false;
}
 
if(isF){
    console.log(count);
}else {
    console.log("invalid IP");
}

--------------------------
标题： VLAN 资源池 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
VLAN是一种对 局域网 设备进行逻辑划分的技术，为了标识不同的VLAN，引入VLAN ID(1-4094之间的整数)的概念。定义一个VLAN ID的资源池(下称VLAN资源池)，资源池中连续的VLAN用开始VLAN-结束VLAN表示，不连续的用单个整数表示，所有的VLAN用英文逗号连接起来。现在有一个VLAN资源池，业务需要从资源池中申请一个VLAN，需要你输出从VLAN资源池中移除申请的VLAN后的资源池。

输入描述:

第一行为字符串格式的VLAN资源池，第二行为业务要申请的VLAN，VLAN的取值范围为[1,4094]之间的整数。

输出描述:

从输入VLAN资源池中移除申请的VLAN后字符串格式的VLAN资源池，输出要求满足题目描述中的格式，并且按照VLAN从小到大升序输出。

如果申请的VLAN不在原VLAN资源池内，输出原VLAN资源池升序排序后的字符串即可。

示例1
输入

1-5

2

输出

1,3-5

说明

原VLAN资源池中有VLAN 1、2、3、4、5，从资源池中移除2后，剩下VLAN 1、3、4、5，按照题目描述格式并升序后的结果为1,3-5。

示例2
输入

20-21,15,18,30,5-10

15

输出

5-10,18,20-21,30

说明

原VLAN资源池中有VLAN 5、6、7、8、9、10、15、18、20、21、30，从资源池中移除15后，资源池中剩下的VLAN为  5、6、7、8、9、10、18、20、21、30，按照题目描述格式并升序后的结果为5-10,18,20-21,30。

示例3
输入

5,1-3

10

输出

1-3,5

说明

原VLAN资源池中有VLAN 1、2、3，5，申请的VLAN 10不在原资源池中，将原资源池按照题目描述格式并按升序排序后输出的结果为1-3,5。

备注:

输入VLAN资源池中VLAN的数量取值范围为[2-4094]间的整数，资源池中VLAN不重复且合法([1,4094]之间的整数)，输入是乱序的。

解题思路
遍历vlan资源池

1、申请的vlan是单独的，则直剔除

2、申请的vlan在区间中

Vlan等于区间最小值，则区间变为vlan+1 – 区间最大值
Vlan等于区间最大值，则区间变为区间最小值 – vlan-1
Vlan等于区间最小值+1，则区间变为两段：区间最小值和vlan+1 – 区间最大值
Vlan等于区间最大值-1，则区间变为两段：区间最小值 – vlan-1和区间最大值
Vlan在区间中间，则区间变为两段：区间最小值 – vlan-1和vlan+1 – 区间最大值
代码
// let strs = readLine().split(",");
// let  n = Number(readLine());
let strs = "20-21,15-16,18,30,5-10".split(",");
let  n = Number("16");
 
let len = strs.length;
let list = [];  //vlan集合
 
for(let i=0; i<len; i++){
    let temp = strs[i].split("-");
    if(temp.length==1 ){    //是一个单独数字
        if(Number(strs[i]) != n){ //不是业务申请的vlan加入集合中
            list.push(strs[i]);
        }
    }else {
        let min = Number(temp[0]);
        let max = Number(temp[1]);
        if(min>n || max<n){
            list.push(strs[i]);  //非业务申请的vlan直接加入集合中
        }else if(min==n){
            if(max-min==1){
                list.push(temp[1]);
            }else{
                list.push((min+1) + "-" + max);  //申请的vlan等于连续vlan的最小值
            }
        }else if(max==n){
            if(max-min==1){
                list.push(temp[0])
            }else{
                list.push(min + "-" + (max-1));  //申请的vlan等于连续vlan的最大值
            } 
        }else {
            if(min != n-1){
                list.push(min + "-" + (n-1));
            }else {
                list.push(temp[0]);  //申请的vlan-1等于连续vlan的最小值
            }
            if(n+1 != max){
                list.push((n+1) + "-" +max);
            }else {
                list.push(temp[1]);  //申请的vlan+1等于连续vlan的最大值
            }
        }
    }
}
 
list.sort((a,b)=>{  //对list进行排序
    let tempA = a.split("-");
    let tempB = b.split("-");
    if(Number(tempA[0]) < Number(tempB[0])){
        return -1;
    }
    return 1;
});
 
let res = "";
for(let i=0; i<list.length; i++){
    res += list[i];
    if(i!=list.length-1){
        res += ",";
    }
}
 
console.log(res);

--------------------------
标题：We Are A Team | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
总共有n个人在机房，每个人有一个标号（1 <= 标号 <=n），他们分成了多个团队，需要你根据收到的m条消息判定指定的两个人是否在一个团队中，具体的：
1、消息构成为：a b c，整数a、b分别代表了两个人的标号，整数c代表指令。
2、c==0代表a和b在一个团队内。
3、c==1代表需要判定a和b的关系，如果a和b是一个团队，输出一行“we are a team”，如果不是，输出一行“we are not a team”。

4、c为其它值，或当前行a或b超出1~n的范围，输出“da pian zi”。

输入描述:

1、第一行包含两个整数n, m(1 <= n, m <= 100000)，分别表示有n个人和m条消息。
2、随后的m行，每行一条消息，消息格式为:a b c (1 <= a, b <= n, 0 <= c <= 1)。

输出描述:

1、c==1时，根据a和b是否在一个团队中输出一行字符串，在一个团队中输出“we are a team”，不在一个团队中输出“we are not a team”。

2、c为其他值，或当前行a或b的标号小于1或者大于n时， 输出字符串 “da pian zi”。

3、如果第一行n和m的值超出约定的范围时，输出字符串"NULL"。

示例1
输入

5 6

1 2 0

1 2 1

1 5 0

2 3 1

2 5 1

1 3 2

输出

we are a team

we are not a team

we are a team

da pian zi

说明

第2行定义了1和2是一个团队

第3行要求进行判定，输出"we are a team"

第4行定义了1和5是一个团队，自然2和5也是一个团队

第5行要求进行判定，输出"we are not a team"

第6行要求进行判定，输出"we are a team"

第7行c为其它值，输出"da pian zi"

解题思路
1、新建一个teams做为所有team的集合

2、当c=0的时候，遍历teams，如果其中有team包含a，则表示b也属于该team，或者有team

      包含b，则表示a也属于该team；如果有两个team，一个包含a，一个包含b，则对两个team

      进行合并

3、当c=1的时候，遍历teams，如果有team同时包含a和b，则表示a和b为一个team，反之不

      为同一个team

代码
let s = readLine().split(" ").map(Number);
//let s = "4 4".split(" ").map(Number);
//let s = "5 6".split(" ").map(Number);
 
let n = s[0];
let m = s[1];
let teams  = []; //所有teams的集合
 
// let test = ["1 2 0",
//             "3 4 0",
//             "2 3 0",
//             "1 4 1"];
//let test = ["1 2 0","1 2 1","1 5 0","2 3 1","2 5 1","1 3 2"];
 
if(n<1 || n>100000 || m<1 || m>100000){ //越界了
    console.log("NULL");
}else {
    for(let i=0;i<m;i++){
 
        let str = readLine().split(" ").map(Number);
        //let str = test[i].split(" ").map(Number);
 
        let a = str[0];
        let b = str[1];
        let c = str[2];
 
        if(a<1 || a>n || b<1 || b>n || (c!=0 && c!=1)){ //a,b越界，c只能0和1
            console.log("da pian zi");
        }else if(c==0){
            let hasTeam = false;    //a和b是否有了team
            let teamIndex = -1;
            let isCombine = false;
            for(let j=0;j<teams.length;j++){
                if(teams[j].includes(a)){   //team中有了a，则b也是其中成员
                    teams[j].push(b);
                    if(hasTeam){    //已经有了team，可以进行合并
                        teams[teamIndex].forEach(v=>{
                            if(!teams[j].includes(v)){
                                teams[j].push(v); 
                            }
                        })
                        isCombine = true;
                        break;
                    }
                    teamIndex = j;
                    hasTeam = true;
                    continue;
                }
                if(teams[j].includes(b)){   //team中有了b，则a也是其中成员
                    teams[j].push(a);
                    if(hasTeam){
                        teams[teamIndex].forEach(v=>{
                            if(!teams[j].includes(v)){
                                teams[j].push(v); 
                            }
                        })
                        isCombine = true;
                        break;
                    }
                    teamIndex = j;
                    hasTeam = true;
                }
            }
            if(isCombine){
                teams.splice(teamIndex,1);    //剔除合并过的team
            }
            if(!hasTeam){   //a和b都没有team，则新建team加入teams的集合中
                let team = [];
                team.push(a);
                team.push(b);
                teams.push(team);
            }
        }else {
            let isATeam = false;
            for(let j=0;j<teams.length;j++){
                if(teams[j].includes(a) && teams[j].includes(b)){   //a和b同时在一个team中
                    isATeam = true;
                }
            }
            console.log(isATeam ? "we are a team" : "we are not a team");
        }
    }
}

--------------------------
标题：一种 字符串压缩 表示的解压 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
有一种简易压缩算法：针对全部由小写英文字母组成的字符串，将其中连续超过两个相同字母的部分压缩为连续个数加该字母，其他部分保持原样不变。例如：字符串“aaabbccccd”经过压缩成为字符串“3abb4cd”。 请您编写解压函数，根据输入的字符串，判断其是否为合法压缩过的字符串，若输入合法则输出解压缩后的字符串，否则 输出字符串 “!error”来报告错误。

输入描述:

输入一行，为一个ASCII字符串，长度不会超过100字符，用例保证输出的字符串长度也不会超过100字符

输出描述:

若判断输入为合法的经过压缩后的字符串，则输出压缩前的字符串；若输入不合法，则输出字符串“!error”。

示例1
输入

4dff

输出

ddddff

说明

4d扩展为dddd，故解压后的字符串为ddddff

示例2
输入

2dff

输出

!error

说明

两个d不需要压缩，故输入不合法

示例3
输入

4d@A

输出

!error

说明

全部由小写英文字母组成的字符串压缩后不会出现特殊字符@和大写字母A，故输入不合法

解题思路
遍历字符串 ，判断是否为数字：

1）是数字且大于小于3，则记录下来num；否则输出error

2）如果是小写字母，则判断num是否存在：

             a、如存在，则判断后面字符是否与之相同：

                        1、如不同则通过num进行解压；

                        2、如相同则输出error

             b、如不存在，则判断后面两个字符是否都与之相同：

                        1、如不同，则直接拼接

                        2、如相同，则输出error

3）其余情况输出error

代码
let str = readLine();
//let str = "aa10v4a";
 
let res = "";
let num = -1;   //压缩数字（初始化为-1）
let len = str.length;
 
let numReg = new RegExp("^[0-9]{1}$");
let caseReg = new RegExp("^[a-z]{1}$");
 
for(let i=0; i<len; i++){
    let c = str[i];
    if(numReg.test(c)){   //判断是否为数字
        let numTemp = Number(c);
        if(i == len-1){   //数字是最后一个，则输出error
            res = "!error";
            break;
        }else if(num == -1){
            if(numTemp==0 || (numTemp<3 && numTemp>0 && caseReg.test(str[i+1]))){
                res = "!error";
                break;
            }else{
                num = Number(c);
            }
        }else{
            num = Number(String(num) + c);  //多位数
        }
    }else if(caseReg.test(c)){ //判断是否为小写字母
        if(num>=3){ //存在压缩数字则进行解压
            if((i!=len-1 && c==str[i+1]) || (c == res.charAt(res.length-1))){ //判断后面一个字符是否与之相等，如果相等则error
                res = "!error";
                break;
            }
            for(let j=0; j<num; j++){   //按照数字进行解压
                res+=c;
            }
            num = -1;   //数字需要重置
        }else {
            if(i<len-2 && c==str[i+1] && c==str[i+2]){  //不能出现相邻的三个及以上字符相同
                res = "!error";
                break;
            }
            res += c;
        }
    }else { //非数字和非小写字母返回error
        res = "!error";
        break;
    }
}
 
console.log(res);

--------------------------
标题：两数之和绝对值最小 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
给定一个从小到大的有序整数序列（存在正整数和负整数） 数组 nums ，请你在该数组中找出两个数，其和的绝对值(|nums[x]+nums[y]|)为最小值，并返回这个绝对值。
每种输入只会对应一个答案。但是，数组中同一个元素不能使用两遍。

输入描述:

一个通过空格分割的有序整数序列字符串，最多1000个整数，且整数数值范围是 -65535~65535。

输出描述:

两数之和绝对值最小值

示例1
输入 ：

-3 -1 5 7 11 15

输出 ：

2

说明 ：

因为 |nums[0] + nums[2]| = |-3 + 5| = 2 最小，所以返回 2

解题思路
使用双层循环进行两两计算，请求出最小绝对值

代码
let nums = readLine().split(" ").map(Number);
//let nums = "-3 -1 5 11 7 15".split(" ").map(Number);
 
let n = nums.length;
let min = Number.MAX_VALUE;
 
for(let i=0;i<n-1;i++){
    for(let j=i+1;j<n;j++){
        let count = Math.abs(nums[i] + nums[j]);    //进行绝对值计算
        min = Math.min(count, min);
    }
}
 
console.log(min);
--------------------------
标题： 九宫格 按键输入 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
九宫格按键输入，有英文和数字两个模式，默认是数字模式，数字模式直接输出数字，英文模式连续按同一个按键会依次出现这个按键上的字母，如果输入“/”或者其他字符，则循环中断，输出此时停留的字母。

数字和字母的对应关系如下，注意0只对应空格：

1（,.）2（abc）3（def） 
4（ghi）5（jkl）6（mno）
7（pqrs）8（tuv）9（wxyz）
# 0（空格）/

输入一串按键，要求输出屏幕显示

1、#用于切换模式，默认是数字模式，执行#后切换为英文模式； 
2、/表示延迟，例如在英文模式下，输入22/222，显示为bc，数字模式下/没有效果；
3、英文模式下，多次按同一键，例如输入22222，显示为b；

输入描述:

输入范围为数字0~9和字符 ‘#’、‘/’，输出屏幕显示，例如， 
在数字模式下，输入1234，显示 1234 

在英文模式下，输入1234，显示 ,adg

输出描述:

输出屏幕显示的字符

示例1
输入

2222/22

输出

222222

说明

默认数字模式，字符直接显示，数字模式下/无效

示例2
输入

#2222/22

输出

ab

说明

#进入英文模式，连续的数字输入会循环选择字母，直至输入/，故第一段2222输入显示a，第二段22输入显示b

示例3
输入

#222233

输出

ae

说明

#进入英文模式，连续的数字输入会循环选择字母，直至输入其他数字，故第一段2222输入显示a，第二段33输入显示e

解题思路
1、将按键上的字符放入集合中，且索引为按键数字

2、新建isEn（是否英文输入）为false，如果遇到#将isEn置反

      temp=“”为上次输入数字（只有英文输入状态有值）

      count=0为同一数字按键次数

3、当isEn为false时，输入若为“/”，直接跳过；若为数字，直接输出

4、当isEn为true时

输入为“/”，若temp为空，直接跳过；若不为空，则通过count求得temp数字上的字符输出，并将temp和count初始化
输入为数字，如数字=temp，count+1，如此刻为最后一个字符，通过count求得temp数字上的字符输出；如数字不等于temp，则通过count求得temp数字上的字符输出，并将temp=此次输入数字，count=1，如此次为最后一个字符，则也需要通过count求得temp数字上的字符输出
输入为#，isEn置为false，若temp不为空，则通过count求得temp数字上的字符输出，并将temp和count初始化
代码
let s = readLine();
//let s = "#222233";
 
var temp = "";   //上一次的数字按键
var sb = "";   //输出字符串
var count = 0;  //按键次数
var strings = [" ",",.","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"];
let isEn = false;   //英文输入
let len = s.length;
 
    for(let i=0;i<len;i++){
        let c = s.charAt(i); //本次的按键
        if(c == "#"){  //中英文切换
            isEn = !isEn;
            if (temp!=""){  //temp有值，说明有字符需要输出
                uotput(temp);
                count = 0;  //输出完，count和temp初始化
                temp = "";
            }
            continue;
        }
        if(isEn){
            /**
             * 英文输入
             */
            if(temp == ""){
                if(c == "/"){
                    continue;
                }
                temp = c;
                count = 1;
                if(i==len-1){   //最后一个
                    uotput(c);
                    break;
                }
            }else if(temp != c){   //按键数字发生变化，需要输出字符
                uotput(temp);
                if(c == "/"){
                    count = 0;
                    temp = "";
                }else {
                    count = 1;
                    temp = c;
                    if(i==len-1){   //最后一个
                        uotput(c);
                        break;
                    }
                }
            }else {
                count++;
                if(i==len-1){   //最后一个
                    uotput(c);
                }
            }
        }else {
            /**
             * 数字输入
             */
            if(c == "/"){  //数字中的/没有意义
                continue;
            }
            sb += c;   //数字直接输出
        }
    }
 
    console.log(sb);
    
function uotput( str){  //输出文字
 
    let strIndex = Number(str);   //上一次的按键（数字）
    if(strIndex==0){
        sb += " "; //0只有空格
    }else {
        let strLen = strings[strIndex].length;    //数字上的字符长度
        let index = count%strLen == 0 ? strLen-1 : count%strLen-1; //找到数字按钮上的对应字母位置
        sb += strings[strIndex].charAt(index);
    }
}

--------------------------
标题：书籍叠放 | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
书籍的长、宽都是整数对应 (l,w)。如果书A的长宽度都比B长宽大时，则允许将B排列放在A上面。
现在有一组规格的书籍，书籍叠放时要求书籍不能做旋转，请计算最多能有多少个规格书籍能叠放在一起。

输入描述:

输入: books = [[20,16],[15,11],[10,10],[9,10]]

说明： 总共4本书籍，第一本长度为20宽度为16；第二本书长度为15宽度为11，依次类推，最后一本书长度为9宽度为10.

输出描述:

输出: 3 

说明: 最多3个规格的书籍可以叠放到一起, 

从下到上依次为: [20,16],[15,11],[10,10]

示例1
输入

[[20,16],[15,11],[10,10],[9,10]]

输出

3

说明

说明: 最多3个规格的书籍可以叠放到一起, 从下到上依次为: [20,16],[15,11],[10,10]

解题思路
将书籍从大到小进行排列。

将第一本书（最大的书）放在最下面，同时作为第一个参照物；遍历参照物后面的书籍，找到最近的满足长和宽都小于参照物的书进行叠加，同时将其作为第二个参照物，再遍历第二个参照物后面的书籍进行比较，以此类推。。。直至所有书遍历完成。最终参照物的个数则是书籍叠放的最大规格。

我的答案
// let books = [[20,16],[15,11],[10,10],[9,10]]
let books = [[15,11],[20,16],[10,10],[9,10], [9, 9]]

books.sort((a,b) => {
    if(a[0] > b[0] && a[1] > b[1]){
        return -1
    }
    if(a[0] < b[0] && a[1] < b[1]){
        return 1
    }
    return b[0] - a[0]
})

let needBooks = books.reduce((a, b, i) => {
    if(i === 0){
        return [b]
    }
    let ref = a[a.length - 1]
    for(let j=i; j books[j][0] && ref[1]>books[j][1]){
            return [...a, books[j]]
        }
    }
    return a
    
}, [])

console.log(needBooks)
     
代码
/**
 * 筛选出所有书籍
 */
// let str = readine().replace("[[","")
//                     .replace("]]","")
//                     .split("],\\[");
let str = "[[20,16],[15,11],[10,10],[9,10]]".replace("[[","")
                    .replace("]]","")
                    .split("],[");
 
let list = [];
 
for(let i=0; i<str.length; i++){
    let shuji = str[i].split(",");
    let length = Number(shuji[0]);  //长
    let width = Number(shuji[1]); //宽
    let ints = [];
    ints.push(length);
    ints.push(width);
    list.push(ints);
}
 
/**
 * 书籍按照长和宽进行降序排列
 */
list.sort((a, b) => {
    if(a[0]<b[0] || (a[0]==b[0] && a[1]<b[1])){
        return 1;
    }
    return -1;
});
 
//第一个参照物
let lenDown = list[0][0];
let widDown = list[0][1];
let count = 1;  //规格
 
for(let i=1;i<list.length;i++){
    let length = list[i][0];
    let width = list[i][1];
    if(lenDown>length && widDown>width){    //长和宽同时满足
        lenDown = length;
        widDown = width;
        count++;
    }
}
 
console.log(count);

--------------------------
标题：乱序整数序列两数之和绝对值最小 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一个随机的整数（可能存在正整数和负整数） 数组 nums ，请你在该数组中找出两个数，其和的绝对值(|nums[x]+nums[y]|)为最小值，并返回这个两个数（按从小到大返回）以及绝对值。
每种输入只会对应一个答案。但是，数组中同一个元素不能使用两遍。

输入描述:

一个通过空格分割的有序整数序列字符串，最多1000个整数，且整数数值范围是 [-65535, 65535]。

输出描述:

两数之和绝对值最小值

示例1
输入

-1 -3 7 5 11 15

输出

-3 5 2

说明

因为 |nums[0] + nums[2]| = |-3 + 5| = 2 最小，所以返回 -3 5 2

解题思路
使用双层循环进行两两计算，请求出最小绝对值

代码
let strings = readLine().split(" ").map(i=>parseInt(i));
//let nums = "-1 -3 7 5 11 15".split(" ").map(i=>parseInt(i));
 
let n = nums.length;
let min = Number.MAX_VALUE;
let num1 = 0;
let num2 = 0;
 
for(let i=0;i<n-1;i++){
    for(let j=i+1;j<n;j++){
        let a = nums[i];
        let b = nums[j];
        let count = Math.abs(a+b);
        min = Math.min(count, min);
        if(min==count){
            num1 = a;
            num2 = b;
        }
    }
}
 
console.log(num1+" "+num2+" "+min);

--------------------------
标题：事件推送 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
同一个数轴X上有两个点的 集合 A={A1, A2, …, Am}和B={B1, B2, …, Bn}，Ai和Bj均为正整数，A、B已经按照从小到大排好序，A、B均不为空，给定一个距离R(正整数)，列出同时满足如下条件的所有（Ai, Bj）数对：

1）Ai <= Bj  

2）Ai, Bj之间的距离小于等于R

3）在满足1）2）的情况下，每个Ai只需输出距离最近的Bj

4）输出结果按Ai从小到大的顺序排序

输入描述:

第一行三个正整数m，n，R

第二行m个正整数，表示集合A

第三行n个正整数，表示集合B

输入限制：

1<=R<=100000，1<=n,m<=100000，1<=Ai,Bj<=1000000000

输出描述:

每组数对输出一行Ai和Bj，以空格隔开

示例1
输入

4 5 5

1 5 5 10

1 3 8 8 20

输出

1 1

5 8

5 8

解题思路
刚开始看到Ai，Bj之间距离的时候，我以为是i到j的距离。后来看到例一上10和20没有配对，猜测距离应该是Bj与Ai的差值（Ai<Bj）

根据题意进行简单的双层循环。

代码
let m = Number(readLine());
let n = Number(readLine());
let R = Number(readLine());
// let m = Number("4");
// let n = Number("5");
// let R = Number("5");
 
let a = readLine().split(" ").map(i=>parseInt(i));
let b = readLine().split(" ").map(i=>parseInt(i));
// let a = "1 5 5 10".split(" ").map(i=>parseInt(i));
// let b = "1 3 8 8 20".split(" ").map(i=>parseInt(i));
 
let list = [];
 
for(let i=0;i<a.length;i++){    //遍历A数组
 
    let ints = [];    //用来放置A、B数字
    let index = 0;  //B数组下标
    while (index<b.length){  //
        if(a[i]<=b[index] && b[index]-a[i]<=R){
            ints[0] = a[i];
            ints[1] = b[index];
            list.push(ints);
            break;
        }
        index++;    //因为两数组都是从大到小排列，index可以公用
    }
}
 
list.forEach(e=>{
    console.log(e[0]+" "+e[1]);
});

--------------------------
标题：仿LISP运算 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
LISP语言唯一的语法就是括号要配对。
形如 (OP P1 P2 ...)，括号内元素由单个空格分割。
其中第一个元素OP为操作符，后续元素均为其参数，参数个数取决于操作符类型
注意：参数 P1, P2 也有可能是另外一个嵌套的 (OP P1 P2 ...)
当前OP类型为 add / sub / mul / div（全小写），分别代表整数的加减乘除法
简单起见，所有 OP 参数个数均为 2
举例:
- 输入：(mul 3 -7) 输出：-21
- 输入：(add 1 2) 输出：3
- 输入：(sub (mul 2 4) (div 9 3)) 输出：5
- 输入：(div 1 0) 输出：error
题目涉及数字均为整数，可能为负；不考虑32位溢出翻转，计算过程中也不会发生32位溢出翻转
除零错误时，输出 "error"，除法遇除不尽， 向下取整 ，即 3/2 = 1

输入描述:

输入为长度不超过512的字符串，用例保证了无语法错误

输出描述:

输出计算结果或者“error”

示例1
输入

(div 12 (sub 45 45))

输出

error

说明

45减45得0，12除以0为除零错误，输出error

示例2
输入

(add 1 (div -7 3))

输出

-2

说明

-7除以3向下取整得-3，1加-3得-2

解题思路
看到这种计算题，就要想到使用栈。

1、通过空格对输入的字符串进行分割。

2、对步骤1获取的数组进行遍历。将数字和符号放入各自的数组中。

对于符号的判断，我们使用了比较取巧的方法：包含a的为加法，包含b的为减法，包含m的为乘法，包含v的为除法

3、如果碰到”）“，则开始进行计算，从数字数组中取最后面的两个数字，从符号数组中取最后面的符号进行计算。

代码
//(sub (mul 2 4) (div 9 3))
// add / sub / mul / div
 
let s = readLine().split(" ");  //输入可以按照空格分割长数组
//let s = "(div 12 (sub 45 45))".split(" ");  //输入可以按照空格分割长数组
//let s = "(add 1 (div -7 3))".split(" ");
 
let fuhao = [];   //符合堆栈
let num = [];    //数字堆栈
let isE = false;    //除0表示计算错误
 
for(let i=0;i<s.length;i++){
    if(s[i].includes("a")){ //如果包含a则表示+
        fuhao.push("+");
    }else if(s[i].includes("b")){   //如果包含b则表示-
        fuhao.push("-");
    }else if(s[i].includes("m")){   //如果包含m则表示*
        fuhao.push("*");
    }else if(s[i].includes("v")){   //如果包含v则表示/
        fuhao.push("/");
    }else if(s[i].includes(")")){   //如果包含)则表示需要进行计算
        let temp = "";   //）前面的数字
        for(let j=0;j<s[i].length;j++){   //包含）的字符串需要筛选出数字
            if(s[i].charAt(j)==')'){    //考虑到都有多个）,需要计算多次
                if(temp.length!=0){   //如果是0表示已经计算过一次
                    num.push(Number(temp));   //将数字放入数堆栈中
                    temp = "";  //需要置空（这一步很关键）
                }
                let b = num.pop();  //第二个数
                let a = num.pop();  //第一个数
                let f = fuhao.pop(); //符号
                if(f=="/" && b==0){ //除数为0则退出，输出error
                    isE = true;
                    break;
                }else {
                    num.push(jisuan(a,b,f));    //将计算完的数据放入数堆栈中进入下次的计算
                }
            }else {
                temp += s[i].charAt(j);  //不到）都表示数字（主要考虑到多位数）
            }
        }
    }else {
        num.push(Number(s[i]));
    }
    if(isE){break;}
}
 
if(isE){
    console.log("error");
}else {
    console.log(num.pop());
}
 
function jisuan( a, b, f){
    switch (f){
        case "+":
            return a+b;
        case "-":
            return a-b;
        case "*":
            return a*b;
        case "/":
            return Math.floor(a/b);  //向下取整
    }
    return 0;
}

--------------------------
标题：信道分配 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
算法工程师 小明面对着这样一个问题，需要将通信用的信道分配给尽量多的用户：

信道的条件及分配规则如下：

1)     所有信道都有属性：”阶”。阶为r的信道的容量为2^r比特；

2)     所有用户需要传输的数据量都一样：D比特；

3)     一个用户可以分配多个信道，但每个信道只能分配给一个用户；

4)     只有当分配给一个用户的所有信道的容量和>=D，用户才能传输数据；

给出一组信道资源，最多可以为多少用户传输数据？

输入描述:

第一行，一个数字R。R为最大阶数。

0<=R<20

第二行，R+1个数字，用空格隔开。

代表每种信道的数量Ni。按照阶的值从小到大排列。

0<=i<=R, 0<=Ni<1000.

第三行，一个数字D。

D为单个用户需要传输的数据量。

0<D<1000000

输出描述:

一个数字，代表最多可以供多少用户传输数据。

示例1
输入

5

10 5 0 1 3 2

30

输出

4

说明

最大阶数为5.

信道阶数：0       1    2    3    4    5

信道容量 ：1       2    4    8    16  32  

信道个数：10     5    0    1    3    2

单个用户需要传输的数据量为30

可能存在很多分配方式，举例说明：

分配方式1：

1)     32*1 = 32

2)     32*1 = 32

3)     16*2 = 32

4)     16*1 + 8*1 + 2*3 = 30

剩下2*2 + 1*10=14不足以再分一个用户了。

分配方式2：

1)     16*1 + 8*1 + 2*3 = 30

2)     16*1 + 2*2 + 1*10 = 30

3)     32*1 = 32

4)     32*1 = 32

剩下16*1=16不足以再分一个用户了。

分配方式3：

1)     16*1 + 8*1 + 2*3 = 30

2)     16*1 + 2*2 + 1*10 = 30

3)     16*1 + 32*1 = 48

4)     32*1 = 32

恰好用完。

虽然每种分配方式剩下的容量不同，但服务的用户数量是一致的。因为这个问题中我们只关心服务的用户数，所以我们认为这些分配方式等效。

解题思路
题目需要我们尽可能的分配最多的用户，也就是每个用户在满足信道需求的情况下信道容量要尽可能的小。

将所有信道求出并放入集合中
先将单独容量大于所需容量的信道剔除，因为它单独就能满足用户，不能让他与其他信道相加而浪费资源。
取出集合中最大的信道（count），
用（D-count=chazhi）求出还差多少信道满足需求。
取出集合中与chazhi最近的信道进行相加（count），如果和满足信道需求，则重复步骤3；如不满足，则重复步骤4
当所有信道相加都不满足需求时，程序结束！
代码
let R = Number(readLine());
let nInput = readLine().split(" ").map(i=>parseInt(i));
 
// let R = Number("5");
// let nInput = "10 5 0 1 3 2".split(" ").map(i=>parseInt(i));
 
let N = [];
for(let i=0;i<=R;i++){
    N[i] = nInput[i];
}
 
let D = Number(readLine());
//let D = Number("30");
let list = [];
 
let res = 0;    //支持用户数量
for(let i=0;i<=R;i++){
    for(let j=0;j<N[i];j++){
        let num = Math.pow(2,i);  //信道容量
        if(num>=D){ //信道容量大于用户需求时直接满足
            res++;
            continue;
        }
        list.push(num);
    }
}
 
let isEnough = true;    //是否够一个用户使用
while (isEnough){
    let count = list[list.length-1];    //取最大的信道
    list.splice(list.length-1,1); //取完需要剔除
    while (count<D && isEnough){
        let min = Number.MAX_VALUE;
        let minindex = 0;
        let temp = 0;
        for(let i = 0;i<list.length;i++){
            temp+=list[i];
            let chazhi =  Math.abs(D-count-list[i]);    //求出与所需信道最接近的信道
            min = Math.min(min, chazhi);
            if(min == chazhi){
                minindex = i;
            }
        }
        count+=list[minindex];
        list.splice(minindex,1);
        if(count>=D){
            res++;
            break;
        }
        if(count+temp<D){   //总共的信道不够一个用户使用
            isEnough = false;
        }
    }
}
console.log(res);

--------------------------
标题：停车场车辆统计 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
特定大小的停车场，数组 cars []表示，其中1表示有车，0表示没车。车辆大小不一，小车占一个车位（长度1），货车占两个车位（长度2），卡车占三个车位（长度3），统计停车场最少可以停多少辆车，返回具体的数目。

输入描述:

整型 字符串数组 cars[]，其中1表示有车，0表示没车，数组长度小于1000。

输出描述:

整型数字字符串，表示最少停车数目。

示例1
输入

1,0,1

输出

2

说明

1个 小车 占第1个车位

第二个车位空

1个小车占第3个车位

最少有两辆车

示例2
输入

1,1,0,0,1,1,1,0,1

输出

3

说明

1个货车占第1、2个车位

第3、4个车位空

1个卡车占第5、6、7个车位

第8个车位空

1个小车占第9个车位

最少3辆车

代码
let cars = readLine().split(",");
//let cars = "1,1,0,0,1,1,1,0,1".split(",");
 
let count = 0;  //1的个数
let res = 0;
 
for(let i=0;i<cars.length;i++){
    if(cars[i]=="1"){
        count++;
    }else{
        if(count!=0){   //只要1的数量不是0则记为1辆车
            res++;
            count = 0;
        }
        continue;
    }
    if(count==3 || i==cars.length-1){ //3个1为1辆卡车直接计数
        res++;
        count = 0;
    }
}
 
console.log(res);

--------------------------
标题：关联子串 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定两个字符串str1和str2，如果字符串str1中的字符，经过 排列组合 后的字符串中，只要有一个字符串是str2的子串，则认为str1是str2的关联子串。
若str1是str2的关联子串，请返回子串在str2的起始位置；
若不是关联子串，则返回-1。
示例1：
输入：str1="abc",str2="efghicabiii"
输出：5
解释：str2包含str1的一种排列组合（"cab")，此组合在str2的字符串起始位置为5（从0开始计数）
示例2：str1="abc",str2="efghicaibii"
输出：-1。
预制条件：

输入的字符串只包含小写字母；

两个字符串的长度范围[1, 100,000]之间

若str2中有多个str1的组合子串，请返回第一个子串的起始位置。

输入描述:

输入两个字符串，分别为题目中描述的str1、str2。

输出描述:

如果str1是str2的关联子串，则返回子串在str2中的起始位置。

如果str1不是str2的关联子串，则返回-1。

若str2中有多个str1的组合子串，请返回最小的起始位置。

示例1
输入

abc efghicabiii

输出

5

说明

str2包含str1的一种排列组合（"cab")，此组合在str2的字符串起始位置为5（从0开始计数）

示例2
输入

abc efghicaibii

输出

-1

说明

“abc”字符串中三个字母的各种组合（abc、acb、bac、bca、cab、cba），str2中均不包含，因此返回-1

备注:

输入的字符串只包含小写字母；

两个字符串的长度范围[1, 100,000]之间

解题思路
1、从str2的第一个字符开始，循环截取str1长度的字符串

2、将截取的字符串与str1进行比较，如果每个字符都能对上，则表示为关联子串，返回起始位置；若遍历到最后都不存，则返回-1

代码
//let strings = readLine().split(" ");
let strings = "abc efghicaibii".split(" ");
 
let str1 = strings[0];
let str2 = strings[1];
let n1 = str1.length;
let n2 = str2.length;
let index = -1;
 
for(let i=0;i<=n2-n1;i++){
    if(isFMatch(str1,str2.substring(i,i+n1))){  //将字符串2进行字符串1长度的切割
        index = i;
        break;
    }
}
 
console.log(index);
 
function isFMatch( str1, str2){
 
    let count = 0;
    let len = str1.length;
    let list = [];
    for(let i=0;i<len;i++){
        list.push(str2.charAt(i));   //将需要匹配的字符串转换成列表
    }
 
    for(let i=0;i<len;i++){
        for(let j=0;j<list.length;j++){
            if(str1.charAt(i)==list[j]){    //如果此字符串匹配成功
                list.splice(j,1); //移除此字符串
                count++;    //匹配成功次数加1
                break;
            }
        }
    }
 
    if(count==len){ //如果匹配次数等于字符串长度则成功
        return true;
    }
 
    return false;
}

--------------------------
标题：出错的或电路 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
某生产 门电路 的厂商发现某一批次的或门电路不稳定，具体现象为计算两个二进制数的或操作时，第一个二进制数中某两个比特位会出现交换，交换的比特位置是随机的，但只交换这两个位，其他位不变。很明显，这个交换可能会影响最终的或结果，也可能不会有影响。为了评估影响和定位出错的根因，工程师需要研究在各种交换的可能下，最终的或结果发生改变的情况有多少种。

输入描述:

第一行有一个正整数N，其中1 \leq N \leq 10000001≤N≤1000000。

第二行有一个长为N的二进制数，表示与电路的第一个输入数，即会发生比特交换的输入数。

第三行有一个长为N的二进制数，表示与电路的第二个输入数。注意第二个输入数不会发生比特交换。

输出描述:

输出只有一个整数，表示会影响或结果的交换方案个数。

示例1
输入

3

010

110

输出

1

说明

原本010和110的或结果是110，但第一个输入数可能会发生如下三种交换：

1. 交换第1个比特和第2个比特，第一个输入数变为100，计算结果为110，计算结果不变

2. 交换第1个比特和第3个比特，第一个输入数变为010，计算结果为110，计算结果不变

3. 交换第2个比特和第3个比特，第一个输入数变为001，计算结果为111，计算结果改变

故只有一种交换会改变计算结果。

示例2
输入

6

011011

110110

输出

4

说明

原本011011和110110的或结果是111111，但第一个输入数发生如下比特交换会影响最终计算结果：

1. 交换第1个比特和第3个比特，第一个输入数变为110011，计算结果变为110111

2. 交换第1个比特和第6个比特，第一个输入数变为111010，计算结果变为111110

3. 交换第3个比特和第4个比特，第一个输入数变为010111，计算结果变为110111

4. 交换第4个比特和第6个比特，第一个输入数变为011110，计算结果变为111110

其他的交换都不会影响计算结果，故输出4。

解题思路
或运算 ：同位置两个只要一个非0就等于1

根据或运算特性，说明只有第二个数中0的位置会受第一个数的影响；

第一个数在第二个数0的位置上

        如果是0，则会受到第一个数中1的个数的影响

        如果是1，则会受到第一个数中0的个数的影响

代码
let n = Number(readLine());
let s1 = readLine();
let s2 = readLine();
// let n = Number("6");
// let s1 = "011011";
// let s2 = "110110";
 
let list = [];
let oneToZero = 0;  //第一个为1，第二个为0
let zeroToZero = 0;  //第一个为0，第二个为1
let one = 0;    //第一个数中1的个数
let zero = 0;   //第一个数中0的个数
 
for(let i=0;i<n;i++){
    if(s1.charAt(i)=='0'){
        zero++;
        if(s2.charAt(i)=='0'){
            zeroToZero++;
            list.push(1);  //受第一个数中1的影响
        }
    }else{
        one++;
        if(s2.charAt(i)=='0'){
            oneToZero++;
            list.push(0);  //受第一个数中0的影响
        }
    }
}
 
let res = 0;
 
for(let i=0;i<list.length;i++){
    if(list[i]==0){
        res+=zero;  //受0的影响则加0的个数
    }else {
        res+=one;   //受1的影响则加1的个数
    }
}
 
console.log(res - zeroToZero*oneToZero);

--------------------------
标题：分班 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
幼儿园两个班的小朋友在排队时混在了一起，每位小朋友都知道自己是否与前面一位小朋友是否同班，请你帮忙把同班的小朋友找出来。

小朋友的编号为整数，与前一位小朋友同班用Y表示，不同班用N表示。

输入描述:

输入为空格分开的小朋友编号和是否同班标志。

比如：6/N 2/Y 3/N 4/Y，表示共4位小朋友，2和6同班，3和2不同班，4和3同班。

其中，小朋友总数不超过999，每个小朋友编号大于0，小于等于999。

不考虑输入格式错误问题。

输出描述:

输出为两行，每一行记录一个班小朋友的编号，编号用空格分开。且：

1、编号需要按照大小 升序排列 ，分班记录中第一个编号小的排在第一行。

2、若只有一个班的小朋友，第二行为空行。

3、若输入不符合要求，则直接 输出字符串 ERROR。

示例1
输入

1/N 2/Y 3/N 4/Y

输出

1 2

3 4

说明

2的同班标记为Y，因此和1同班。

3的同班标记为N，因此和1、2不同班。

4的同班标记为Y，因此和3同班。

所以1、2同班，3、4同班，输出为

1 2

3 4

解题思路
需要一个boolean值来转换班级

True：一班

        N：表示在二班

        Y：表示在一班

False：二班

        N：表示在一班

        Y：表示在二班

代码
//let strings = readline().split(" ");
let strings = "6/N 8/Y 6/N 10/Y".split(" ");
 
let list1 = [];  //一班
let list2 = [];  //二班
 
let b = true;   //用来转换班级 true为一班 false为二班
let isError = false;
let isDigit = new RegExp("^[0-9]*$")
 
for(let i=0; i<strings.length; i++){
    let x = strings[i].split("/");
    if(!isDigit.test(x[0])){
        isError = true;
        break;
    }
    let stu = Number(x[0]);
    if((x[1] != "N" && x[1] != ("Y"))
        || list1.includes(stu)
        || list2.includes(stu))
    {
        isError = true;
        break;
    }
    if(list1.length == 0){    //第一位直接安排一班
        list1.push(stu);
        continue;
    }
    if(b){  //此时是一班
        if(x[1] == "N"){
            list2.push(stu) ;   //非一班
            b = false;
        }else {
            list1.push(stu);
        }
    } else {    //此时是二班
        if(x[1] == "N"){
            list1.push(stu);   //非二班
            b = true;
        }else {
            list2.push(stu);
        }
    }
 
}
 
if(isError){
    console.log("ERROR");
}else {
    list1.sort((a,b) =>{return a-b});
    list2.sort((a,b) =>{return a-b});
    let res1 = "";
    let res2 = "";
    for(let i=0; i<list1.length; i++){
        res1 += list1[i] + " ";
    }
    for(let i=0; i<list2.length; i++){
        res2 += list2[i] + " ";
    }
    if(list2.length == 0){
        console.log(res1.substring(0, res1.length-1));
    }else if(list1[0] < list2[0]){
        console.log(res1.substring(0, res1.length-1));
        console.log(res2.substring(0, res2.length-1));
    }else {
        console.log(res2.substring(0, res2.length-1));
        console.log(res1.substring(0, res1.length-1));
    }
}

--------------------------
标题：分积木 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
Solo 和koko是两兄弟，妈妈给了他们一大堆积木，每块积木上都有自己的重量。现在他们想要将这些积木分成两堆。哥哥Solo负责分配，弟弟koko要求两个人获得的积木总重量“相等”（根据Koko的逻辑），个数可以不同，不然就会哭，但koko只会先将两个数转成二进制再进行加法，而且总会忘记进位（每个进位都忘记）。如当25（11101）加11（1011）时，koko得到的计算结果是18（10010）：

 11001

+01011

--------

 10010

Solo想要尽可能使自己得到的积木总重量最大，且不让koko哭。

输入描述:

3

3 5 6

第一行是一个整数N(2≤N≤100)，表示有多少块积木；第二行为空格分开的N个整数Ci(1≤Ci≤106)，表示第i块积木的重量。

输出描述:

11

让koko不哭，输出Solo所能获得积木的最大总重量；否则输出“NO”。

示例1
输入

3

3 5 6

输出

11

备注:

如果能让koko不哭，输出Solo所能获得的积木的总重量，否则输出-1。

该样例输出为11。

解释： Solo能获得重量为5和6的两块积木，5转成二级制为101，6转成二进制位110，按照koko的计算方法（忘记进位），结果为11(二进制)。Koko获得重量为3的积木，转成二进制位11(二进制)。Solo和koko得到的积木的重量都是11(二进制)。因此Solo可以获得的积木的总重量是5+6=11（十进制）。

解题思路
在不进位的情况下进行 二进制运算 ，其实就是异或运算。

根据题意，就是需要所有值的 异或运算 最终结果为0

当所有值的异或运算为0，就可以进行平分，只要减去最小的积木重量，solo就能获取最多的积木重量；否则返回No。

代码
let n = Number(readLine());
let arr = readLine().split(" ").map(Number);
// let n = Number("3");
// let arr = "3 5 6".split(" ").map(Number);
 
console.log(getResult(arr));
 
function getResult(arr){
 
    if(arr.length == 2 && arr[0] != arr[1]) return "NO";
    let min = arr[0];
    let sum = min;
    let temp = min;
    for(let i = 1; i<arr.length; i++){
        sum += arr[i];
        min = min< arr[i]?min:arr[i];
        temp ^= arr[i];
    }
    if(temp != 0) {
        return "NO";
    }else{
        return sum-min;
    }
}

--------------------------
标题：分糖果 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
小明从糖果盒中随意抓一把糖果，每次小明会取出一半的糖果分给同学们。

当糖果不能平均分配时，小明可以选择从糖果盒中（假设盒中糖果足够）取出一个糖果或放回一个糖果。

小明最少需要多少次（取出、放回和平均分配均记一次），能将手中糖果分至只剩一颗。

输入描述:

抓取的糖果数（<10000000000）：

15

输出描述:

最少分至一颗糖果的次数：

5

示例1
输入

15

输出

5

备注:

解释：(1)15+1=16;(2)16/2=8;(3)8/2=4;(4)4/2=2;(5)2/2=1;

解题思路
需要用递归对取和放进行模拟从而求出最小次数

代码
var list = [];
let n = Number(readLine());
//let n = Number("15");
 
fentangguo(n,0);    //第一个参数糖果数量，第二个参数是次数（初始化为0）
 
list.sort((a,b)=>{  //从小到大排序
    if(b>a){
        return -1;
    }
    return 1;
});
 
console.log(list[0]);
 
function fentangguo(n,m){
 
    if (n==1) {
        list.push(m);    //只剩一个分糖完毕
        return 1;
    }
    if(n%2==0){
        m++;    //分一次次数加1
        fentangguo(n/2,m);
    }else{
        m++;    //放回或取出次数加1
        fentangguo(n-1,m);
        fentangguo(n+1,m);
    }
    return 0;
}

--------------------------
标题：判断一组 不等式 是否满足约束并输出最大差 | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
给定一组不等式，判断是否成立并输出不等式的最大差(输出浮点数的整数部分)，要求：1）不等式系数为double类型，是一个二维数组；2）不等式的变量为int类型，是一维数组；3）不等式的目标值为double类型，是一维数组；4）不等式约束为字符串数组，只能是：">",">=","<","<=","="，例如,不等式组：
a11*x1+a12*x2+a13*x3+a14*x4+a15*x5<=b1;
a21*x1+a22*x2+a23*x3+a24*x4+a25*x5<=b2;

a31*x1+a32*x2+a33*x3+a34*x4+a35*x5<=b3;

最大差=max{  (a11*x1+a12*x2+a13*x3+a14*x4+a15*x5-b1),   (a21*x1+a22*x2+a23*x3+a24*x4+a25*x5-b2),   (a31*x1+a32*x2+a33*x3+a34*x4+a35*x5-b3)  }，类型为整数(输出浮点数的整数部分)

输入描述:

1）不等式组系数(double类型)：

a11,a12,a13,a14,a15 

a21,a22,a23,a24,a25 
a31,a32,a33,a34,a35
2）不等式变量(int类型)：
x1,x2,x3,x4,x5
3）不等式目标值(double类型)：b1,b2,b3

4)不等式约束(字符串类型):<=,<=,<=

输入： a11,a12,a13,a14,a15;a21,a22,a23,a24,a25;a31,a32,a33,a34,a35;x1,x2,x3,x4,x5;b1,b2,b3;<=,<=,<=

输出描述:

true 或者 false, 最大差

示例1
输入

2.3,3,5.6,7,6;11,3,8.6,25,1;0.3,9,5.3,66,7.8;1,3,2,7,5;340,670,80.6;<=,<=,<=

输出

false 458

示例2
输入

2.36,3,6,7.1,6;1,30,8.6,2.5,21;0.3,69,5.3,6.6,7.8;1,13,2,17,5;340,67,300.6;<=,>=,<=

输出

false 758

解题思路：（就是逻辑题）
1、对输入数据用”;”进行分割，分割后的的数组最后三个数组分别为不等式变量、不等式目标

      值，不等式约束，剩下的都是不等式系数

2、然后根据题意对系数和变量进行×、+处理

3、通过目标值和约束进行判断处理，并获取最大值

代码
let strings = readLine().split(";");
//let strings = "2.36,3,6,7.1,6;1,30,8.6,2.5,21;0.3,69,5.3,6.6,7.8;1,13,2,17,5;340,67,300.6;<=,>=,<=".split(";");
 
let length = strings.length;
let bianliang = strings[length-3].split(",").map(i=>Number(i)); //不等式变量
let mubiao = strings[length-2].split(",").map(i=>Number(i)); //不等式目标值
let ys = strings[length-1].split(","); //不等式约束
 
let m = ys.length;  //约束的数量等于数组的数量
let n = bianliang.length;  //变量的数量等于数组中数据的数量
 
let doubles = [];  //不等式系数是二维数组
 
for(let i=0;i<m;i++){
    let xs = strings[i].split(","); //不等式系数
    doubles[i] = new Array;
    for(let j=0;j<n;j++){
        doubles[i][j] = Number(xs[j]);  //将不等式系数放入double类型二维数组
    }
}
 
let isYueshu = true;
let max = 0;
 
for (let i=0;i<m;i++){  //循环遍历不等式数组
    let d=0;
    let b = true;
    for(let j=0;j<n;j++){
        d+=doubles[i][j]*bianliang[j];   //不等式数组值
    }
    max = Math.max(max,d-mubiao[i]);    //求出最大差
    if(ys[i] == ">"){  //等于不等式进行判断
        b = d>mubiao[i];
    }else if(ys[i] == ">="){
        b = d>=mubiao[i];
    }else if(ys[i] == "<"){
        b = d<mubiao[i];
    }else if(ys[i] == "<="){
        b = d<=mubiao[i];
    }else if(ys[i] == "="){
        b = d==mubiao[i];
    }
    if(!b){ //只要一个等式不成立就为false
        isYueshu = false;
    }
}
 
console.log(isYueshu+" "+  parseInt(max));

--------------------------
标题：判断字符串 子序列  | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定字符串 target和 source, 判断 target 是否为 source 的子序列。
你可以认为 target 和  source 中仅包含英文小写字母。字符串 source可能会很长（长度 ~= 500,000），而 target 是个短字符串（长度 <=100）。

字符串的一个子序列是原始 字符串删除 一些（也可以不删除）字符而不改变剩余字符相对位置形成的新字符串。（例如，"abc"是"aebycd"的一个子序列，而"ayb"不是）。

请找出最后一个子序列的起始位置。

输入描述:

第一行为target，短字符串（长度 <=100）

第二行为source，长字符串（长度 ~= 500,000）

输出描述:

最后一个子序列的起始位置， 即最后一个子序列首字母的下标

示例1
输入

abc

abcaybec

输出

3

说明

这里有两个abc的子序列满足，取下标较大的，故返回3

备注:

若在source中找不到target，则输出-1

解题思路
因为是求最后一个子串的第一个字母下标，所以我们从后面向前开始遍历

将target作为外部循环内容，从最后一个字符开始向前遍历。
将source作为内部循环内容，从最后一个字符开始向前遍历。
当source出现字符与target字符相同时，计数加一并记录其下标，将其作为下次遍历source初始的下标。接着是target的倒数第二字符。。。以此类推，直至target或source遍历完成
若计数等于target长度，则输出其下标
代码
let target = readLine();
let source = readLine();
// let target = "abc";
// let source = "abcaybec";
 
let n1 = target.length;
let n2 = source.length;
 
let n = 0;
let res = n2;
 
for(let i=n1-1;i>=0;i--){
    for(let j=res-1;j>=0;j--){
        if(target.charAt(i)==source.charAt(j)){
            n++;
            res = j;
            break;
        }
    }
}
 
if(n==n1){
    console.log(res);
}else {
    console.log(-1);
}

--------------------------
标题：区间交集 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一组闭区间，其中部分区间存在交集。任意两个给定区间的交集，称为公共区间（如：[1,2],[2,3]的公共区间为[2,2]，[3,5],[3,6]的公共区间为[3,5]）。公共区间之间若存在交集，则需要合并（如：[1,3],[3,5]区间存在交集[3,3]，须合并为[1,5])。按 升序排列 输出合并后的区间列表。

输入描述:

一组区间列表，

区间数为N：

0 <= N <= 1000；

区间元素为X：

-10000 <= X <= 10000。

输出描述:

升序排列的合并后区间列表

示例1
输入

0 3

1 3

3 5

3 6

输出

1 5

说明

[0,3]和[1,3]的公共区间为[1,3]，[0,3]和[3,5]的公共区间为[3,3]，[0,3]和[3,6]的公共区间为[3,3]，[1,3]和[3,5]的公共区间为[3,3]，[1,3]和[3,6]的公共区间为[3,3]，[3,5]和[3,6]的公共区间为[3,5]，公共区间列表为[[1,3],[3,3],[3,5]]；[1,3],[3,3],[3,5]存在交集，须合并为[1,5]。

示例2
输入

0 3

1 4

4 7

5 8

输出

1 3

4 4

5 7

示例3
输入

1 2

3 4

输出

None

说明

[1,2]和[3,4]无交集

备注:

1、区间元素均为数字，不考虑字母、符号等异常输入。

2、单个区间认定为无公共区间。

代码
let list = [];
//let test = ["0 3","1 4","4 7","5 8"];
//let test = ["1 2","3 4"];
let test = ["0 3","1 3","3 5","3 6"];
 
for(let i=0;i<test.length;i++){
	let x = test[i].split(" ");
	let node = new qujian(x[0], x[1]);
	list.push(node);
}
 
// while (readline()) {
// 	let input = readline().split(" ").map(Number);
// 	let node = new qujian(input[0], input[1]);
// 	list.push(node);
// }
 
let list1 = [];
collection(list);
 
for(let i=0;i<list.length-1;i++){
	for(let j=i+1;j<list.length;j++){
		let a = list[i];
		let b = list[j];
		if(b.left <= a.right){
			let l = Math.max(a.left, b.left);
			let r = Math.min(a.right, b.right);
			let node = new qujian(l, r);
			list1.push(node);
		}
	}
}
 
if(list1.length==0){
	console.log("None");
	return;
}
collection(list1);
let l = list1[0].left;
let r = list1[0].right;
 
for(let i=1; i<list1.length; i++){
	let node = list1[i];
	if(node.left > r){
		console.log(l+" "+r);
		l = node.left;
		r = node.right;
	}else {
		l = Math.min(node.left, l);
		r = Math.max(node.right, r);
	}
}
console.log(l+" "+r);
 
function qujian(l, r){
	this.left = l;
	this.right = r;
}
 
function collection( list){
	list.sort((a,b) => {
		if(a.left==b.left){
			return a.right-b.right;
		}
		return a.left-b.left;
	});
}

--------------------------
标题：叠积木 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
有一堆长方体积木，它们的宽度和高度都相同，但长度不一。小橙想把这堆积木叠成一面墙，墙的每层可以放一个积木，也可以将两个积木拼接起来，要求每层的长度相同。若必须用完这些积木，叠成的墙最多为多少层？

如下是叠成的一面墙的图示，积木仅按宽和高所在的面进行拼接。



输入描述:

输入为一行，为各个积木的长度，数字为正整数，并由空格分隔。积木的数量和长度都不超过5000。

输出描述:

输出一个数字，为墙的最大层数，如果无法按要求叠成每层长度一致的墙，则输出-1。

示例1
输入

3 6 6 3

输出

3

说明

可以每层都是长度3和6的积木拼接起来，这样每层的长度为9，层数为2；也可以其中两层直接用长度6的积木，两个长度3的积木拼接为一层，这样层数为3，故输出3。

示例2
输入

1 4 2 3 6

输出

-1

说明

无法用这些积木叠成每层长度一致的墙，故输出-1。

解题思路
1、每层只能放一个或两个积木

2、积木的总长度可以被积木层数整除

3、积木每层的最小长度为最短积木，最大长度为最短积木和最大积木和（因为一层最多两个积木）

4、根据步骤2对总长度进行分解因子，从最小长度开始，如果因数符合积木要求，则输出层数；如不符合，则输出-1

代码
let strings = readLine().split(" ");
//let strings = "4 5 3 6".split(" ");
 
let list = [];
let count = 0;  //积木总长度
let len = strings.length;
 
for(let i=0;i<len;i++){
    let n = Number(strings[i]);
    count += n;
    list.push(n);    //所有积木集合
}
 
list.sort((a,b)=>{return a-b});
let min = list[len-1];  //最小宽度
let max = list[0] + list[len-1];    //最大宽度（因为最多是两个积木拼接）
let res = -1;
 
for(let i=min;i<=max;i++){
    if(count%i==0){
        let copyList = copyArr(list); //因为要对list进行多次操作，需要copy一下
        if(isSuccess(copyList,i)){
            res = count/i;
            break;
        }
    }
}
 
console.log(res);
 
function copyArr(list){
 
    let len = list.length;
    let copyList = [];
 
    for(let i=0;i<len;i++){
        copyList.push(list[i]);
    }
 
    return copyList;
}
 
/**
 *
 * @param list 积木集合
 * @param n 积木所需宽度
 * @return
 */
function isSuccess(list, n){
 
    let isTrue = true;
 
    while (list.length >0 && isTrue){
        let i = list.length-1;
        if(n==list[i]){
            list.splice(i,1); //最长的一根积木符合要求则剔除进行下次循环
        }else if(n == list[i]+list[0]){
            list.splice(i,1); //最长一根跟最短一根积木之和符合要求则剔除两个积木进行下次循环
            list.splice(0,1);
        }else {
            isTrue = false; //上面两个都不符合则表示无法完成一堵墙
        }
    }
 
    return isTrue;
}

--------------------------
标题：可以组成网络的服务器 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
在一个机房中，服务器的位置标识在 n*m 的整数矩阵网格中，1 表示单元格上有服务器，0 表示没有。如果两台服务器位于同一行或者同一列中紧邻的位置，则认为它们之间可以组成一个 局域网 。
请你统计机房中最大的局域网包含的服务器个数。

输入描述:

第一行输入两个正整数，n和m，0<n,m<=100
之后为n*m的二维数组，代表服务器信息

输出描述:

最大局域网包含的服务器个数。

示例1
输入

2 2

1 0

1 1

输出

3

说明

[0][0]、[1][0]、[1][1]三台服务器相互连接，可以组成局域网

解题思路
新建整数count；二阶数组ints = new int[n][m]

1、遍历二阶数组，获取ints[x][y]=1的横纵坐标x、y，count=1，ints[x][y]=0

2、将步骤中的x，y作为初始坐标

        若x>0且ints[x-1][y]=1，则count++，ints[x-1][y]=0，则重复步骤2

        若y>0且ints[x][y-1]=1，则count++，ints[x][y-1]=0，则重复步骤2

        若x<n-1且ints[x+1][y]=1，则count++，ints[x+1][y]=0，则重复步骤2

        若y<m-1且ints[x][y+1]=1，则count++，ints[x][y+1]=0，则重复步骤2

3、最后求出count的最大值为最大局域网

代码
//var nm = readline().split(" ").map(Number);
var nm = "2 3".split(" ").map(Number);
 
var n = nm[0];
var m = nm[1];
var ints = [];   //网络矩阵
 
let test = ["1 0 1","1 1 1"];
 
for(let i=0; i<n; i++){
    ints[i] = [];
    //let temp = readline().split(" ").map(Number);
    let temp = test[i].split(" ").map(Number);
    for(let j=0; j<m; j++){
        ints[i][j] = temp[j];
    }
}
 
let list = [];
var count;
for(let i=0; i<n; i++){
    for(let j=0; j<m; j++){
        if(ints[i][j] == 1){
            count = 1;
            ints[i][j] = 0;
            internet(i, j);
            list.push(count);
        }
    }
}
 
list.sort((a,b)=>{return b-a});
console.log(list[0]);
 
function internet( x, y){
 
    if(x>0 && ints[x-1][y]==1){
        ints[x-1][y] = 0;
        count++;
        internet(x-1, y);
    }
    if(y>0 && ints[x][y-1]==1){
        ints[x][y-1] = 0;
        count++;
        internet(x, y-1);
    }
    if(x<n-1 && ints[x+1][y]==1){
        ints[x+1][y] = 0;
        count++;
        internet(x+1, y);
    }
    if(y<m-1 && ints[x][y+1]==1){
        ints[x][y+1] = 0;
        count++;
        internet(x, y+1);
    }
}

--------------------------
标题：喊7的次数重排 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
喊7是一个传统的聚会游戏，N个人围成一圈，按顺时针从1到N编号。编号为1的人从1开始喊数，下一个人喊的数字为上一个人的数字加1，但是当将要喊出来的数字是7的倍数或者数字本身含有7的话，不能把这个数字直接喊出来，而是要喊"过"。假定玩这个游戏的N个人都没有失误地在正确的时机喊了"过"，当喊到数字K时，可以统计每个人喊"过"的次数。

现给定一个长度为N的数组，存储了打乱顺序的每个人喊"过"的次数，请把它还原成正确的顺序，即数组的第i个元素存储编号i的人喊"过"的次数。

输入描述:

输入为一行，为空格分隔的喊"过"的次数，注意K并不提供，K不超过200，而数字的个数即为N。

输出描述:

输出为一行，为顺序正确的喊"过"的次数，也由空格分隔。

示例1
输入

0 1 0

输出

1 0 0

说明

一共只有一次喊"过"，那只会发生在需要喊7时，按顺序，编号为1的人会遇到7，故输出1 0 0。注意，结束时的K不一定是7，也可以是8、9等，喊过的次数都是1 0 0。

示例2
输入

0 0 0 2 1

输出

0 2 0 1 0

说明

一共有三次喊"过"，发生在7 14 17，按顺序，编号为2的人会遇到7 17，编号为4的人会遇到14，故输出0 2 0 1 0。

解题思路
1、根据输入的数字相加可以得到喊“过”的次数和总人数

2、根据模拟发现 （ 报数 /总人数）的余数 -1 就等于报数人的下标（下标从0开始所以需要-1）

总人数为5：喊1的下标为0；喊2 的下标为1。。。喊6的下标为0（6%5-1）

3、根据2的规律就可以筛选出符合条件的下标，然后再做叠加的动作

代码
let s = sc.radLine().split(" ").map(i=>parseInt(i));;
//let s = "0 0 0 2 1".split(" ").map(i=>parseInt(i));
let len = s.length;
 
let ints = new Array(len).fill(0);
 
let num = 0;
for(let i=0;i<len;i++){
    num += s[i];     //计算出符合的次数
}
let step = 7;   //直接从7开始
while (num>0){
    if(step%7==0 || String(step).indexOf("7")!=-1){
        ints[(step-1)%len]++;      //同过数组长度算出符合的下标
        num--;      //符合的次数递减
    }
    step++;     //报数的次数递增
}
 
let res = "";
for(let i=0;i<len;i++){
    res+=String(ints[i]);
    if(i == len-1){
        break;
    }
    res+=" ";
}
 
console.log(res);

--------------------------
标题：图像物体的边界 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一个二维数组M行N列，二维数组里的数字代表图片的像素，为了简化问题，仅包含像素1和5两种像素，每种像素代表一个物体，2个物体相邻的格子为边界，求像素1代表的物体的边界个数。

像素1代表的物体的边界指与像素5相邻的像素1的格子，边界相邻的属于同一个边界，相邻需要考虑8个方向（上，下，左，右，左上，左下，右上，右下）。

其他约束：

地图规格约束为：

0<M<100

0<N<100

1）如下图，与像素5的格子相邻的像素1的格子（0,0）、（0,1）、（0,2）、（1,0）、（1,2）、（2,0）、（2,1）、（2,2）、（4,4）、（4,5）、（5,4）为边界，另（0,0）、（0,1）、（0,2）、（1,0）、（1,2）、（2,0）、（2,1）、（2,2）相邻，为1个边界，（4,4）、（4,5）、（5,4）相邻，为1个边界，所以下图边界个数为2。



2）如下图，与像素5的格子相邻的像素1的格子（0,0）、（0,1）、（0,2）、（1,0）、（1,2）、（2,0）、（2,1）、（2,2）、（3,3）、（3,4）、（3,5）、（4,3）、（4,5）、（5,3）、（5,4）、（5,5）为边界，另这些边界相邻，所以下图边界个数为1。注：（2,2）、（3,3）相邻。



输入描述:

第一行，行数M，列数N

第二行开始，是M行N列的像素的二维数组，仅包含像素1和5

输出描述:

像素1代表的物体的边界个数。如果没有边界输出0（比如只存在像素1，或者只存在像素5）。

示例1
输入

6  6

1 1 1 1 1 1

1 5 1 1 1 1

1 1 1 1 1 1

1 1 1 1 1 1

1 1 1 1 1 1

1 1 1 1 1 5

输出

2

说明

参考题目描述部分

示例2
输入

6  6

1 1 1 1 1 1

1 5 1 1 1 1

1 1 1 1 1 1

1 1 1 1 1 1

1 1 1 1 5 1

1 1 1 1 1 1

输出

1

说明

参考题目描述部分

解题思路
1、通过二维 数组遍历 到像素为5的位置，再将其周围的1变为2作为边界；

2、重复步骤1，直至将所有像素为5的周围的1全部变为2；

3、再通过二维数组遍历到像素为2的位置，再将其周围的2变为0清除边界。

        如果两个边界相邻的话，会被一同清除。

        如果两个边界不相邻的话，重复步骤2。

        步骤2执行的次数即为边界个数。

代码
var hang = Number(readLine());
var lie = Number(readLine());
// var hang = Number("6");
// var lie = Number("6");
 
var ints = [];
// var ints = [[1,1,1,1,1,1],
//             [1,5,1,1,1,1],
//             [1,1,1,1,1,1],
//             [1,1,1,1,1,1],
//             [1,1,1,1,1,1],
//             [1,1,1,1,1,5]];
 
for(let i=0;i<hang;i++){
    ints[i] = [];
    let str = readLine().split(" ");
    for(let j=0;j<lie;j++){
        ints[i][j] = Number(str[j]);
    }
}
 
/**
 * 将5周围的1转变为2作为边界
 * 遍历数组找到边界2，将其变为0，再通过递归将其周围的2全部变为0
 * 如果边界相邻则所有的2都会变为0
 */
for(let i=0;i<hang;i++){
    for(let j=0;j<lie;j++){
        if(ints[i][j] == 5){
            if(i>0){    //表示上面有值
                if(ints[i-1][j]==1){    //正上方
                    ints[i-1][j] = 2;   //边界用0表示
                }
                if(j>0){    //表示左边有值
                    if(ints[i-1][j-1]==1){  //左上方
                        ints[i-1][j-1] = 2;
                    }
                }
                if(j<lie-1){//右边有值
                    if(ints[i-1][j+1]==1){  //右上方
                        ints[i-1][j+1] = 2;
                    }
                }
            }
            if(j>0){    //表示左边有值
                if(ints[i][j-1]==1){    //左边
                    ints[i][j-1]=2;
                }
            }
            if(i<hang-1){ //表示下面有值
                if(ints[i+1][j]==1){    //正下方
                    ints[i+1][j]=2;
                }
                if(j>0){    //表示左边有值
                    if(ints[i+1][j-1]==1){  //左下方
                        ints[i+1][j-1] = 2;
                    }
                }
                if(j<lie-1){//右边有值
                    if(ints[i+1][j+1]==1){  //右下方
                        ints[i+1][j+1] = 2;
                    }
                }
            }
            if(j<lie-1){//右边有值
                if(ints[i][j+1]==1){  //右边
                    ints[i][j+1] = 2;
                }
            }
        }
    }
}
 
let count = 0;  //边界个数
for(let i=0;i<hang;i++){
    for(let j=0;j<lie;j++){
        if(ints[i][j]==2){
            count++;
            ints[i][j] = 0;
            qingchuBianjie(i,j);
        }
    }
}
console.log(count);
 
function qingchuBianjie( i, j){
    if(i>0){    //表示上面有值
        if(ints[i-1][j]==2){    //正上方
            ints[i-1][j]=0;
            qingchuBianjie(i-1,j);
        }
        if(j>0){    //表示左边有值
            if(ints[i-1][j-1]==2){  //左上方
                ints[i-1][j-1]=0;
                qingchuBianjie(i-1,j-1);
            }
        }
        if(j<lie-1){//右边有值
            if(ints[i-1][j+1]==2){  //右上方
                ints[i-1][j+1]=0;
                qingchuBianjie(i-1,j+1);
            }
        }
    }
    if(j>0){    //表示左边有值
        if(ints[i][j-1]==2){    //左边
            ints[i][j-1]=0;
            qingchuBianjie(i,j-1);
        }
    }
    if(i<hang-1){ //表示下面有值
        if(ints[i+1][j]==2){    //正下方
            ints[i+1][j]=0;
            qingchuBianjie(i+1,j);
        }
        if(j>0){    //表示左边有值
            if(ints[i+1][j-1]==2){  //左下方
                ints[i+1][j-1]=0;
                qingchuBianjie(i+1,j-1);
            }
        }
        if(j<lie-1){//右边有值
            if(ints[i+1][j+1]==2){  //右下方
                ints[i+1][j+1]=0;
                qingchuBianjie(i+1,j+1);
            }
        }
    }
    if(j<lie-1){//右边有值
        if(ints[i][j+1]==2){  //右边
            ints[i][j+1]=0;
            qingchuBianjie(i,j+1);
        }
    }
}

--------------------------
标题：太阳能板最大面积 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
给航天器一侧加装长方形或正方形的太阳能板（图中的红色斜线区域），需要先安装两个支柱（图中的黑色竖条），再在支柱的中间部分固定太阳能板。但航天器不同位置的支柱长度不同，太阳能板的安装面积受限于最短一侧的那根支柱长度。如图：



现提供一组整形 数组 的支柱高度数据，假设每根支柱间距离相等为1个单位长度，计算如何选择两根支柱可以使太阳能板的面积最大。

输入描述:

10,9,8,7,6,5,4,3,2,1

注：支柱至少有2根，最多10000根，能支持的高度范围1~10^9的整数。柱子的高度是无序的，例子中递减只是巧合。

输出描述:

可以支持的最大太阳能板面积：（10米高支柱和5米高支柱之间）

25

示例1
输入

10,9,8,7,6,5,4,3,2,1

输出

25

备注:

10米高支柱和5米高支柱之间宽度为5，高度取小的支柱高也是5，面积为25。任取其他两根支柱所能获得的面积都小于25。所以最大的太阳能板面积为25。

解题思路
1、从第二根支柱开始向后遍历（第一根无法完成挡板）

2、从当前遍历的支柱向前遍历求出第一根支柱至当前支柱的最大面积

代码
let strings = readLine().split(",");
//let strings ="10,9,8,7,6,5,4,3,2,1".split(",");
let num = [];   //将输入放入整数数组中
 
for(let m=0;m<strings.length;m++){
    num[m] = Number(strings[m]);
}
 
let max = 0;    //最大面积
 
for(let n=1;n<num.length;n++){
    let min = num[n]; //假设当前挡板为最小挡板
    let temp = n-1; //前一个挡板下标
    for(let i=1;i<=n;i++){
        /**
         * 循环计算当前挡板到前面i个挡板的面积并求出最大值
         */
        min = Math.min(min,num[temp--]);   //min 求出前挡板到前面i个挡板最小高度
        max = Math.max(min*i,max);  //min*i 求出前挡板到前面i个挡板的面积
    }
}
 
console.log(max);

--------------------------
标题
标题： 字符串分割 | 时间限制：3秒 | 内存限制：262144K | 语言限制：不限

给定非空字符串s，将该字符串分割成一些子串，使每个子串的ASCII码值的和均为 水仙花数 。

1、若分割不成功，则返回0

2、若分割成功且分割结果不唯一，则返回-1

3、若分割成功且分割结果唯一，则返回分割后子串的数目

输入描述:

1、输入字符串的最大长度为200

输出描述:

根据题目描述中情况，返回相应的结果

示例1
输入

abc

输出

0

说明

分割不成功

示例2
输入

f3@d5a8

输出

-1

说明

分割成功但分割结果不唯一，可以分割为两组，一组"f3"和"@d5a8"，另外一组"f3@d5"和"a8"

示例3
输入

AXdddF

输出

2

说明

成功分割且分割结果唯一，可以分割“AX"(153)和"dddF"(370)成两个子串

备注:

“水仙花数”是指一个三位数，每位上数字的立方和等于该数字本身，如371是“水仙花数”，因为：371 = 3^3 + 7^3 + 1^3

解题思路
1、对输入的字符串逐字进行ASCII码值求和，当满足水仙花数的时候，将剩下的字符串再进行求和判断，计算到最后一位字符也满足水仙花数，则符合 字符分割 +1。

2、在上一个求和判断（步骤1）中，当满足水仙花数的时候不进行分割，而是接着继续逐字求和判断，如果计算到最后一位字符还是满足水仙花数，则也符合分割，符合分割+1。

3、重复步骤2的操作，直至遍历到最后一个字符或遍历到大于999的时候，判断符合分割的情况有几个。只有1的时候符合题意。

题目主要使用到了递归。

代码
var fuhe = 0; //能够实现的方案个数
var zichuan = 1;  //分割出的子串个数
 
let str = readLine();
//let str = "abc";
let res = 0;
 
fenge(str,n);
 
if(fuhe==1){
    res = zichuan;  //只有一种情况符合
}else if(fuhe>1){
    res = -1;   //大于一种情况符合
}
 
console.log(res);
 
function fenge(s, n){
 
    let len = s.length;
    let count = 0;  //ACSII码计数和
    for(let i=0;i<len;i++){
        count+=s.charCodeAt(i);
        if(count>999){  //大于999之后都不符合要求，直接退出
            break;
        }
        if( count>=100 && count<=999){  //水仙数[100,999]之间
            if(isSXS(count)){
                if(i==len-1){
                    fuhe++; //字符串遍历到最后一位都符合水仙数，说明是符合要求的
                    zichuan = ++n;
                }else {
                    let nums = n;
                    fenge(s.substring(i+1), ++nums); //将剩下的字符继续遍历
                }
            }
        }
    }
}
 
function isSXS(i){
 
    let b = parseInt(i/100);  //百位数
    let s = parseInt(i%100/10);   //十位数
    let g = i%100%10;   //个位数
 
    let count = (Math.pow(b,3) + Math.pow(s,3) + Math.pow(g,3));
 
    if(count == i){
        return true;
    }
 
    return false;
}

--------------------------
标题： 字符串 分割 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一个非空字符串S，其被N个‘-’分隔成N+1的子串，给定正整数K，要求除第一个子串外，其余的子串每K个字符组成新的子串，并用‘-’分隔。对于新组成的每一个子串，如果它含有的小写字母比大写字母多，则将这个子串的所有大写字母转换为小写字母；反之，如果它含有的大写字母比小写字母多，则将这个子串的所有小写字母转换为大写字母；大小写字母的数量相等时，不做转换。

输入描述:

输入为两行，第一行为参数K，第二行为字符串S。

输出描述:

输出转换后的字符串。

示例1
输入

3

12abc-abCABc-4aB@

输出

12abc-abc-ABC-4aB-@

说明

子串为12abc、abCABc、4aB@，第一个子串保留，后面的子串每3个字符一组为abC、ABc、4aB、@，abC中小写字母较多，转换为abc，ABc中大写字母较多，转换为ABC，4aB中大小写字母都为1个，不做转换，@中没有字母，连起来即12abc-abc-ABC-4aB-@

示例2
输入

12

12abc-abCABc-4aB@

输出

12abc-abCABc4aB@

说明

子串为12abc、abCABc、4aB@，第一个子串保留，后面的子串每12个字符一组为abCABc4aB@，这个子串中大小写字母都为4个，不做转换，连起来即12abc-abCABc4aB@

解题思路
1、将除了第一个子串外的其他所有子串拼接成一个长字符串

2、对拼接后的长字符串进行K长度的分割

3、对分割出来的字符串进行格式化（题意中的大小写变化）

4、使用”-”将格式化的各子串进行拼接

代码
let n = Number(readLine());
let s = readLine().split("-");
// let n = Number("12");
// let s = "12abc-abCABc-4aB@".split("-");
 
let string = "";
let res = "";
 
for(let i=1;i<s.length;i++){
    string+=s[i];   //将除了第一个子串之外的所有子串拼接成长字符串
}
 
let step; //字符串分割的终点位置
let stringLen =string.length;
for(let i=0; i<=stringLen; i+=n){
    if(i+n > stringLen){
        step = stringLen;
    }else {
        step = i+n;
    }
    res+="-"+geshihua(string.substring(i,step));    //将字符串进行分割并格式化
}
 
console.log(s[0]+res);
 
function geshihua(s){
    let low = 0;  //小写字母数量
    let up = 0; //大写字母数量
    let res = "";
    let len = s.length;
    let upCase = /[A-Z]/;
    let lowCase = /[a-z]/;
    for(let i=0;i<len;i++){  //计算大小写字母数量
        if(lowCase.test(s.charAt(i))){
            low++;
        }else if(upCase.test(s.charAt(i))){
            up++;
        }
    }
    if(low>up){ //小写字母数量大于大写字母数量
        for(let i=0;i<len;i++){
            if(upCase.test(s.charAt(i))){
                res += s.charAt(i).toLowerCase(); //将所有大写字母转换成小写字母
                continue;
            }
            res+=s.charAt(i);
        }
    } else if(low<up){  //大写字母数量大于小写字母数量
        for(let i=0;i<len;i++){
            if(lowCase.test(s.charAt(i))){
                res += s.charAt(i).toUpperCase();    //将所有小写字母转换成大写字母
                continue;
            }
            res+=s.charAt(i);
        }
    }else {
        res = s;
    }
    return res;
}

--------------------------
标题： 字符串 加密 | 时间限制：2秒 | 内存限制：65536K | 语言限制：不限
给你一串未 加密 的字符串str，通过对字符串的每一个字母进行改变来实现加密，加密方式是在每一个字母str[i]偏移特定数组元素a[i]的量，数组a前三位已经赋值：a[0]=1,a[1]=2,a[2]=4。当i>=3时，数组元素a[i]=a[i-1]+a[i-2]+a[i-3]，

例如： 原文 abcde 加密后 bdgkr，其中偏移量分别是1,2,4,7,13。

输入描述:

第一行为一个整数n（1<=n<=1000），表示有n组测试数据，每组数据包含一行，原文str（只含有小写字母，0<长度<=50）。

输出描述:

每组测试数据输出一行，表示字符串的密文

示例1
输入

1

xy

输出

ya

说明

第一个字符x偏移量是1，即为y，第二个字符y偏移量是2，即为a

示例2
输入

2

xy

abcde

输出

ya

bdgkr

说明

第二行输出字符偏移量分别为1、2、4、7、13

解题思路：
看到这种 数组a前三位已经赋值：a[0]=1,a[1]=2,a[2]=4。当i>=3时，数组元素a[i]=a[i-1]+a[i-2]+a[i-3]，就可以直接使用递归了。
先初始化一个26位字母的字符串。
通过递归计算出字符的偏移量，获取字符在字母字符串中的索引位置。索引与偏移量进行相加，再对26取余（防止偏移量过大越界），得到就是加密后的字符在字母字符串的索引。
代码
let zimu = "abcdefghijklmnopqrstuvwxyz";
let n = Number(readLine());
//let n = Number("1");
let list = [];
 
for(let i=0;i<n;i++){
    let s = readLine();
    //let s = "xy";
    let sb = "";
    let len = s.length;
    for(let j=0;j<len;j++){
        let pianyi = jiami(j);
        let index = (zimu.indexOf(s.charAt(j)) + pianyi)%26;    //需要取余，防止pianyi值过大
        sb += zimu.charAt(index);
    }
    list.push(sb);
}
 
for(let i=0;i<list.length;i++){
    console.log(list[i]);
}
 
function jiami(n){
    if(n==0){
        return 1;
    }
    if(n==1){
        return 2;
    }
    if(n==2){
        return 4;
    }
    return jiami(n-1)+jiami(n-2)+jiami(n-3);
}

--------------------------
标题：字符串变换最小字符串 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一个字符串s，最多只能进行一次变换，返回变换后能得到的最小字符串（按照 字典序 进行比较）。

变换规则：交换字符串中任意两个不同位置的字符。

输入描述:

一串小写字母组成的字符串s

输出描述:

按照要求进行变换得到的最小字符串

示例1
输入

abcdef

输出

abcdef

说明

abcdef已经是最小字符串，不需要交换

示例2
输入

bcdefa

输出

acdefb

说明

a和b进行位置交换，可以等到最小字符串

备注:

s是都是小写字符组成

1<=s.length<=1000

解题思路
1、要取最小值，就是将比较小的字符尽可能的移到最前面

2、 遍历字符串 找到最小值，将它放到最前面；如果此时它已经在最前面，则找到第二小值。。。以此类推

代码
//let s = readline();
let s = "bcdefa";
 
let len = s.length;
let listBySort = [];
let chars = [];   //原字符数组
 
for(let i=0; i<len; i++){
    listBySort.push(s.charAt(i));
    chars[i] = s.charAt(i);
}
 
listBySort.sort();   //对字符进行排序
 
let change = ' ';  //需要替换的字符
let minIndex = 0;   //较小的字符下标
let changeIndex = 0;    //需要替换的字符下标
for(let i=0; i<len; i++){
    if(listBySort[i]<s.charAt(i)){  //小字符串在后进行替换
        change = listBySort[i];
        changeIndex = i;
        break;
    }
}
 
if(change != ' '){
    for(let i=len-1; i>=0; i--){
        if(s.charAt(i) == change){
            minIndex = i;
            break;
        }
    }
    chars[minIndex] = chars[changeIndex];
    chars[changeIndex] = change;
}
 
let res = "";
for(let i=0; i<chars.length; i++){
    res+=chars[i];
}
 
console.log(res);

--------------------------
标题：字符串序列判定 | 时间限制：3秒 | 内存限制：262144K | 语言限制：不限
输入两个字符串S和L，都只包含英文小写字母。S长度<=100，L长度<=500,000。判定S是否是L的有效字串。

判定规则：S中的每个字符在L中都能找到（可以不连续），且S在Ｌ中字符的前后顺序与S中顺序要保持一致。（例如，S=" ace "是L="abcde"的一个子序列且有效字符是a、c、e，而"aec"不是有效子序列，且有效字符只有a、e）

输入描述:

输入两个字符串S和L，都只包含英文小写字母。S长度<=100，L长度<=500,000。

先输入S，再输入L，每个字符串占一行。

输出描述:

S串最后一个有效字符在L中的位置。（首位从0开始计算，无有效字符返回-1）

示例1
输入

ace

abcde

输出

4

示例2
输入

fgh

abcde

输出

-1

解题思路
对两个字符串进行遍历。（比较简单）

代码
// let S = readline();
// let L = readline();
// let S = "ace";
// let L = "abcde";
let S = "fgh";
let L = "abcde";
 
let n = 0;
let m = 0;
 
while (m<L.length && n<S.length){
    if(S.charAt(n)==L.charAt(m)){
        n++;
    }
    m++;
}
 
if(n == S.length){
    console.log(m-1);
}else {
    console.log(-1);
}

--------------------------
标题：字符串比较 | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
给定字符串A、B和正整数V，A的长度与B的长度相等， 请计算A中满足如下条件的最大连续子串的长度：

1、该连续子串在A和B中的 位置和长度均相同 。

2、该连续子串|A[i] – B[i]|之和小于等于V。其中|A[i] – B[i]|表示两个字母 ASCII码之差的绝对值 。

输入描述:

输入为三行：

第一行为字符串A，仅包含小写字符，1 <= A.length <=1000。

第二行为字符串B，仅包含小写字符，1 <= B.length <=1000。

第三行为正整数V，0<= V <= 10000。

输出描述:

字符串最大连续子串的长度，要求该子串|A[i] – B[i]|之和小于等于V。

示例1
输入：

xxcdefg

cdefghi

5

输出：

2

说明：

字符串A为xxcdefg，字符串B为cdefghi，V=5。

它的最大连续子串可以是cd->ef,de->fg,ef->gh,fg->hi，所以最大连续子串是2。

解题思路
如例1：

新建整数类型count为连续子串 ASCII码 之差的绝对值之和

遍历两个字符串，因为长度相等，所以公用一个索引

1、A[0]-B[0]=x-c=120-99=21>5，不符合要求

x x cdefg

c defghi

2、A[1]-B[1]=x-d=120-100=20>5，不符合要求

x x cdefg

c d efghi

3、A[2]-B[2]=c-e=|99-101|=2<5，符合要求，count=2；

xx c defg

cd e fghi

4、A[3]-B[3]=d-f=|100-102|=2，count =count+2=4<5，符合要求，count=4；

xx cd efg

cd ef ghi

5、A[4]-B[4]=e-g=|101-103|=2，count=count+2=6>5；不符合要求，第一个子串为 cd->ef ；这时count需要减去第一个符合要求的A[2]-B[2]=2，count=4；

xx c de fg

c d e fg hi

6、A[5]-B[5]=f-h=|102-104|=2，count=count+2=6>5，不符要求，第二个子串为 de->fg； 这时count需要减去第一个符合要求的A[3]-B[3]=2，count=4；

xx cd ef g

cd ef gh i

7、A[6]-B[6]=g-i=|103-105|=2，count=count+2=6>5，不符要求，第二个子串为 ef->gh； 这时count需要减去第一个符合要求的A[4]-B[4]=2，count=4；此时是最后一个字符，count<5,则 fg->hi 也是符合要求的。

xx cde fg

cd efg hi

代码
let s1 = readline();
let s2 = readline();
let n = Number(readline());
// let s1 = "xxcdefg";
// let s2 = "cdefghi";
// let n = Number("5");
 
let max = 0;
let length = 0;
let list = [];     //用列表存放符合要求的数
 
list.push(Math.abs(s1.charCodeAt(0) - s2.charCodeAt(0)));      //假设第一个字母就符合要求
let count = list[0];        //第一个字母ASCII码之差的绝对值
 
for ( let i=1; i<s1.length; i++) {
 
    let temp = Math.abs(s1.charCodeAt(i) - s2.charCodeAt(i));
 
    list.push(temp);     //直接将本次的ASCII码之差的绝对值添加进列表
    count += Math.abs(temp);      //求最新的绝对值和
 
    if ( count <= n ) {
        length = list.length;       //若符合要求则最长的为列表的长度
    } else {
        count -= list[0];   //不符合则减去并删除列表第一个数
        list.splice(0, 1);
    }
    max = Math.max( length, max);
}
 
console.log(max);

--------------------------
标题：字符统计及重排 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给出一个仅包含字母的 字符串 ，不包含空格，统计字符串中各个字母（区分大小写）出现的次数，并按照字母出现次数从大到小的顺序输出各个字母及其出现次数。如果次数相同，按照自然顺序进行排序，且小写字母在大写字母之前。

输入描述:

输入一行，为一个仅包含字母的字符串。

输出描述:

按照字母出现次数从大到小的顺序输出各个字母和字母次数，用英文分号分隔，注意末尾的分号；字母和次数间用英文冒号分隔。

示例1
输入

xyxyXX

输出

x:2;y:2;X:2;

说明

每个字符出现的个数都是2，故x排在y之前，而小写字母x在X之前

示例2
输入

abababb

输出

b:4;a:3;

说明

b的出现个数比a多，故b排在a之前

代码
//let s = readline();
//let s = "xyxyXX";
let s = "abababb";
 
let map = new Map();
 
for(let i=0; i<s.length; i++){
    if(!map.has(s.charAt(i))){
        map.set(s.charAt(i), 1)
    }else{
        map.set(s.charAt(i), map.get(s.charAt(i))+1);     //将输入内容转成键值对
    }
}
 
let entryList = Array.from(map);
let upReg = new RegExp("^[A-Z]{1}$");
let lowReg = new RegExp("^[a-z]{1}$");
 
entryList.sort((a,b)=>{
    if (b[1]>a[1]) {      //按出现次数顺序排序
        return 1;
    }
    if(b[1]<a[1]){      //按出现次数顺序排序
        return -1;
    }
    if(lowReg.test((b[0])) && upReg.test(a[0])){     //限制小写在前
        return 1;
    }
    if(lowReg.test((a[0])) && upReg.test((b[0]))){     //限制小写在前
        return -1;
    }
    if(b[0] < a[0] ){       //按字母顺序排序
        return 1;
    }
    return -1;
});
 
let res = "";
for(let i=0; i<entryList.length; i++){
    res += entryList[i][0] + ":";
    res += entryList[i][1] + ";";
}
 
console.log(res);

--------------------------
标题：学生方阵 | 时间限制：1秒 | 内存 限制：262144K | 语言限制：不限
学校组织活动，将学生排成一个矩形方阵。请在矩形方阵中找到最大的位置相连的男生数量。这个相连位置在一个直线上，方向可以是水平的、垂直的、呈对角线的或者反对角线的。
注：学生个数不会超过10000.

输入描述:

输入的第一行为矩阵的行数和列数，接下来的n行为矩阵元素，元素间用“,”分隔。

输出描述:

输出一个整数，表示矩阵中最长的位置相连的男生个数。

示例1
输入

3,4

F,M,M,F

F,M,M,F

F,F,F,M

输出

3

解题思路
1、将学生矩阵转化成二维数组，方便计算。

2、遍历二维数组，将每一位男生都作为一个起点，计算出其水平、垂直、对角线和反对角线的连续男生数量

水平：从（0,1）向后计算连续男生数量（横坐标不变，纵坐标递增）

F

M

M

F

F

M

M

F

F

F

F

M

垂直：从（0,1）向下计算连续男生数量（横坐标递增，纵坐标不变）

F

M

M

F

F

M

M

F

F

F

F

M

对角线：从（0,1）向右下角计算连续男生数量（横坐标递增，纵坐标递增）

F

M

M

F

F

M

M

F

F

F

F

M

反对角线：从（0,1）向左下角计算连续男生数量（横坐标递减，纵坐标递增）

F

M

M

F

F

M

M

F

F

F

F

M

对于水平向左，垂直向上，右上对角线和左上反对角线的情况已经被覆盖了，所有无需考虑。

代码
let strings = readLine().split(",").map(i=>parseInt(i));
//let strings = "3,4".split(",").map(i=>parseInt(i));
 
var row = strings[0];  //行
var col = strings[1];  //列
 
var str = [];
var list = [];   //用来存放所有位置相连男生个数
//let test = [ "F,M,M,F", "F,M,M,F", "F,F,F,M"];
 
for(let i=0;i<row;i++){ //将矩形方阵模拟为二维数组
    let rowStrs = readLine().split(",");
    //let rowStrs = test[i].split(",");
    str[i] = [];
    for(let j=0;j<col;j++){
        str[i][j] = rowStrs[j];
    }
}
 
for(let i=0;i<row;i++){
    for(let j=0;j<col;j++){
        if(str[i][j] == "M") getRes(i,j);
    }
}
 
list.sort(); //对集合进行升序，取最后一个
 
console.log(list[list.length-1]);
 
/**
 *
 * @param x 横坐标
 * @param y 纵坐标
 */
function getRes( x, y){
 
    let n = 1;
    let a,b;
 
    if(y<col){ //从此点水平向右
        a = x;
        b = y;
        while (b<col-1 && str[a][++b] == "M"){
            n++;
        }
        list.push(n);
        n = 1;
    }
    if(x<row){ //从此点垂直向下
        a = x;
        b = y;
        while (a<row-1 && str[++a][b] == "M"){
            n++;
        }
        list.push(n);
        n = 1;
    }
    if(x<row && y<col){ //从此点对角线
        a = x;
        b = y;
        while ((a<row-1 && b<col-1) && str[++a][++b] == "M"){
            n++;
        }
        list.push(n);
        n = 1;
    }
    if(x>=0 && y<col){ //从此点反对角线
        a = x;
        b = y;
        while ((a>0 && b<col-1) && str[--a][++b] == "M"){
            n++;
        }
        list.push(n);
    }
}

--------------------------
标题：寻找相同子串 | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
给你两个字符串 t 和 p ，要求从 t 中找到一个和 p 相同的连续子串，并输出该字串第一个字符的下标。

输入描述:

输入文件包括两行，分别表示字符串 t 和 p ，保证 t 的长度不小于 p ，且 t 的长度不超过1000000，p 的长度不超过10000。

输出描述:

如果能从 t 中找到一个和 p 相等的连续子串，则输出该子串第一个字符在t中的下标（下标从左到右依次为1,2,3,…）；如果不能则输出”No”；如果含有多个这样的子串，则输出第一个字符下标最小的。

示例1
输入

AVERDXIVYERDIAN

RDXI

输出

4

解题思路
通过 indexOf方法 找到下标，根据题意需要+1

代码
let t = readLine();
let p = readLine();
// let t = "AVERDXIVYERDIAN";
// let p = "RDXI";
 
if(t.length>1000000){
    console.log("No");
}
 
if(p.length>t.length && p.length>10000){
    console.log("No");
}
 
console.log(t.indexOf(p) == -1? "No" : t.indexOf(p)+1);
--------------------------
标题：寻找身高相近的小朋友 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
小明今年升学到小学一年级，来到新班级后发现其他小朋友们身高参差不齐，然后就想基于各小朋友和自己的身高差对他们进行排序，请帮他实现排序。

输入描述:

第一行为正整数H和N，0<H<200，为小明的身高，0<N<50，为新班级其他小朋友个数。
第二行为N个正整数H1-HN，分别是其他小朋友的身高，取值范围0<Hi<200（1<=i<=N），且N个正整数各不相同。

输出描述:

输出排序结果，各正整数以空格分割。和小明身高差绝对值最小的小朋友排在前面，和小明身高差绝对值最大的小朋友排在最后，如果两个小朋友和小明身高差一样，则个子较小的小朋友排在前面。

示例1
输入

100 10

95 96 97 98 99 101 102 103 104 105

输出

99 101 98 102 97 103 96 104 95 105

说明

小明身高100，班级学生10个，身高分别为95 96 97 98 99 101 102 103 104 105，按身高差排序后结果为：99 101 98 102 97 103 96 104 95 105。

解题思路
看到这种对单个数组进行排序，就想到简单的 冒泡排序 （不了解的可以百度一下）

传统的冒泡排序是用数字与数字比较，这里使用的是绝对值，其实道理是一样的。

代码
let input = readLine().split(" ").map(Number);
let ints = readLine().split(" ").map(Number);
// let input = "100 10".split(" ").map(Number);
// let ints = "95 96 97 98 99 101 102 103 104 105".split(" ").map(Number);
 
let H = input[0];
let N = input[1];
 
for(let i=0; i<N-1; i++){
    for(let j=0; j<N-1-i; j++){
 
        let a = Math.abs(ints[j]-H);
        let b = Math.abs(ints[j+1]-H);
 
        if(a>b || (a==b && ints[j]>ints[j+1])){
            let temp = ints[j];
            ints[j] = ints[j+1];
            ints[j+1] = temp;
        }
    }
}
 
let res = "";
for(let i=0; i<N; i++){
    res += ints[i];
    if(i != N-1){
        res += " ";
    }
}
 
console.log(res);

--------------------------
标题：德州扑克 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
五张牌，每张牌由牌大小和花色组成，牌大小2~10、J、Q、K、A，牌花色为红桃、黑桃、梅花、方块四种花色之一。 判断牌型:
牌型1， 同花顺 ：同一花色的顺子，如红桃2红桃3红桃4红桃5红桃6。
牌型2，四条：四张相同数字 + 单张，如红桃A黑桃A梅花A方块A + 黑桃K。
牌型3，葫芦：三张相同数字 + 一对，如红桃5黑桃5梅花5 + 方块9梅花9。
牌型4，同花：同一花色，如方块3方块7方块10方块J方块Q。
牌型5，顺子：花色不一样的顺子，如红桃2黑桃3红桃4红桃5方块6。
牌型6，三条：三张相同 + 两张单。
牌型7，其他。
说明：
1）五张牌里不会出现牌大小和花色完全相同的牌。

2）编号小的牌型较大，如同花顺比四条大，依次类推。

3）包含A的合法的顺子只有10 J Q K A和A 2 3 4 5，类似K A 2 3 4的序列不认为是顺子。

输入描述:

输入由5行组成，每行为一张牌大小和花色，牌大小为2~10、J、Q、K、A，花色分别用字符H、S、C、D表示红桃、黑桃、梅花、方块。

输出描述:

输出牌型序号，5张牌符合多种牌型时，取最大的牌型序号输出。

示例1
输入

4 H

5 S

6 C

7 D

8 D

输出

5

说明

4 5 6 7 8构成顺子，输出5

示例2
输入

9 S

5 S

6 S

7 S

8 S

输出

1

说明

既是顺子又是同花，输出1，同花顺

解题思路
将牌面数字和其数量作为键值对放入map函数中
New一个int数组，其索引0,1,2,3代表H,S,C,D，其值代表各花色个数
如果int数组中，有其中一个数值为5，则代表同花
判断map的长度：
如果map的长度为5，则说明5张牌都不一样。可以判断是否为顺子，也需要判断其是否为同花。需要注意的是，A可以作为1，也可以做为14。
map如果有value值为4，则为四条；如果有value值为3，则判断map长度，如果长度为2，则为葫芦；如果长度为3，则为三条
代码
let numList = [];
let map = new Map();    //数字，数字个数键值对
let color = Array(4).fill(0);   //H、S、C、D 红黑梅方
 
//let test = ["A S","J C","J H","J S","J D"];
//let test = ["4 H","5 S","6 C","7 D","8 D"];
// let test = ["A S","J S","K S","Q S","10 S"];
 
for(let i=0; i<5; i++){
 
    let input = readLine().split(" ");
    //let input = test[i].split(" ");
 
    let num;
    switch (input[0]){
        case "A":
            num = 1;
            break;
        case "J":
            num = 11;
            break;
        case "Q":
            num = 12;
            break;
        case "K":
            num = 13;
            break;
        default:
            num = Number(input[0]);
    }
 
    if(map.has(num)){
        map.set( num, map.get(num)+1);
    }else{
        map.set( num, 1);
    }
    numList.push(num);
 
    let hs = input[1];
    if(hs == "H"){
        color[0]++;
    }else if(hs == "S"){
        color[1]++;
    }else if(hs == "C"){
        color[2]++;
    }else {
        color[3]++;
    }
}
 
let isTongHua = false;
 
if(color[1]==5 || color[1]==5 || color[2]==5 || color[3]==5){   //只要其中一个花色有5张为同花
    isTongHua = true;
}
 
let res = 7;
 
if(map.size == 5){
    numList.sort((a,b)=>{return a-b});  //排序方便判断顺子
    let isShunZi = isShunzi(numList);
    if(isShunZi){
        res = isTongHua ? 1 : 5;
    }else {
        res = isTongHua ? 4 : 7;
    }
}else {
    map.forEach((v, k)=>{
        if(v == 4){  //有四条一样的
            return res = 2;
        }else if(v == 3){    //有三条一样的
            return res = map.size == 2 ? 3 : 6;    //如果只有牌面只有两个数字则是三带二，否则三带两单
        }
    })
}
 
console.log(res);
 
function isShunzi( list){
 
    let b = true;
    let index = 1;
    let isA = false;
 
    if(list[0]==1 && list[1]!=2){   //如果第一张为A，且第二张不为2
        index = 2;
        isA = true;
    }
 
    for(let i=index; i<5; i++){
        if(list[i] != list[i-1]+1){
            b = false;
            break;
        }
        if(i==4 && isA && list[4]!=13){
            b = false;
        }
    }
 
    return b;
}

--------------------------
标题：快递运输 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
一辆运送快递的货车，运送的快递均放在大小不等的长方体快递盒中，为了能够装载更多的快递，同时不能让货车超载，需要计算最多能装多少个快递。

注：快递的体积不受限制，快递数最多1000个，货车载重最大50000。

 输入描述:

一辆运送快递的货车

第一行输入每个快递的重量，用英文逗号分隔，如：5,10,2,11

第二行输入货车的载重量，如：20

不需要考虑异常输入。

输出描述:

输入最多能装多少个快递，如：3

例题1
输入

5,10,2,11

20

输出

3

说明

货车的载重量为20，最多只能放三个快递5、10、2，因此输出3

解题思路
因为要装最多的货，所以货物的重量越轻越好。将货物从小到大排序，遍历相加，当大于载重量的时候退出。

代码
// let nums = readline().split(",").map(Number);   //把快递以逗号分割放入数组中
// let n = Number(readline());
let nums = "5,10,2,11".split(",").map(Number);   //把快递以逗号分割放入数组中
let n = Number("20");
 
let len = nums.length;
 
nums.sort((a,b)=>{if(b>a) return -1});  //对快递进行从小到大排序
let res = 0;
let num = 0;
for(let i=0; i<len; i++){
    res += nums[i];
    if(res>n){      //若大于载重量则推出循环
        break;
    }
    num++;
}
 
console.log(num);

--------------------------
标题：打印任务排序 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
某个打印机根据打印 队列 执行打印任务。打印任务分为九个优先级，分别用数字1~9表示，数字越大优先级越高。打印机每次从队列头部取出第一个任务A，然后检查队列余下任务中有没有比A优先级更高的任务，如果有比A优先级高的任务，则将任务A放到队列尾部，否则就执行任务A的打印。请编写一个程序，根据输入的打印队列，输出实际的打印顺序

输入描述:

输入一行，为每个任务的 优先级 ，优先级之间用逗号隔开，优先级取值范围是1~9

输出描述:

输出一行，为每个任务的打印顺序，打印顺序从0开始，用逗号隔开

示例1
输入

9,3,5

输出

0,2,1

说明

队列头部任务的优先级为9，最先打印，故序号为0；接着队列头部任务优先级为3，队列中还有优先级为5的任务，优先级3任务被移到队列尾部；接着打印优先级为5的任务，故其序号为1；最后优先级为3的任务的序号为2

示例2
输入

1,2,2

输出

2,0,1

说明

队列头部任务的优先级为1，被移到队列尾部；接着顺序打印两个优先级为2的任务，故其序号分别为0和1；最后打印剩下的优先级为1的任务，其序号为2

解题思路
1、将所有打印任务的各自的序列号和优先级都放入各自的集合中，再将集合放入双向队列中。

2、从队列中的第一个元素开始向后遍历，判断优先级是否最高，如果是取出其集合，继续第二个元素；如不是则将其放入队列最后，重复步骤2。

3、当所有元素全部取出，则获取任务序列的排序。再经过序号和其处理顺序的交换就看得到原始任务的处理顺序。

代码
let strings = readLine().split(",").map(i=>parseInt(i));
//let strings = "9,3,5".split(",").map(i=>parseInt(i));
let len = strings.length;
 
let mask = [];
let list = [];
 
for(let i=0;i<len;i++){
    let num = strings[i];
    let temp = [];
    temp.push(i);    //使用下标方便最后获取执行顺序
    temp.push(num);
    mask.push(temp);
}
 
while (mask.length>0){
    let first = mask[0][1];    //队列最前的任务
    let isDayin = true; //是否进行打印
    for (let l of mask){
        if(first<l[1]){ //如果发现队列中有大于最前的
            let temp = mask.shift();
            mask.push(temp); //将最前的移动到队列最后
            isDayin = false;
            break;
        }
    }
    if(isDayin){
        let dayin = mask.shift();
        list.push(dayin[0]);  //打印完就移除任务，并将任务下标添加到list
    }
}
 
let res = [];
for (let i=0;i<len;i++){
    res[list[i]] = i;   //list的值与下标进行交换就是所需要的结果
}
 
console.log(res.join(","));

--------------------------
标题：执行时长 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
为了充分发挥GPU 算力 ，需要尽可能多的将任务交给GPU执行，现在有一个任务数组，数组元素表示在这1秒内新增的任务个数且每秒都有新增任务，假设GPU最多一次执行n个任务，一次执行耗时1秒，在保证GPU不空闲情况下，最少需要多长时间执行完成

输入描述:

第一个参数为GPU一次最多执行的任务个数，取值范围[1, 10000]
第二个参数为任务数组长度，取值范围[1, 10000]
第三个参数为任务数组，数字范围[1, 10000]

输出描述:

执行完所有任务最少需要多少秒

示例1
输入

3

5

1 2 3 4 5

输出

6

说明

一次最多执行3个任务，最少耗时6s

示例2
输入

4

5

5 4 1 1 1

输出

5

说明

一次最多执行4个任务，最少耗时5s

解题思路
如果此刻新增的任务个数小于等于GPU一次执行任务个数，则表示此刻任务全部执行完成；

如果此刻新增任务个数大于GPU一次执行任务个数，则表示任务有余留，剩余任务需要下一秒进行执行。

最后剩余的任务数如果能整除GPU的一次执行任务个数，则直接取其商；

如果不能整除，则商取整并+1。

代码
let n = Number(readLine());   //一秒钟内能执行的任务个数
let len = Number(readLine());
let ints = readLine().split(" ").map(i=>parseInt(i));
// let n = Number("3");   //一秒钟内能执行的任务个数
// let len = Number("7");
// let ints = "1 2 3 4 5 6 7".split(" ").map(i=>parseInt(i));
 
let second = 0; //计时
let more = 0;   //剩余未完成的任务个数
for(let i=0;i<len;i++){
    if(ints[i]+more<=n){
        more = 0;
    }else {
        more = ints[i] + more -n;   //此刻任务数与上秒剩余的任务数减去n
    }
    second++;
}
 
if(more%n==0){
    second += more/n;   //任务正好完成
}else {
    second += parseInt(more/n) + 1;
}
 
console.log(second);

--------------------------
标题：找到它 | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
找到它是个小游戏，你需要在一个 矩阵 中找到给定的单词。假设给定单词HELLOWORLD，在矩阵中只要能找到H->E->L->L->O->W->O->R->L->D连成的单词，就算通过。

注意区分英文字母大小写,并且你只能上下左右行走，不能走回头路。

输入描述:

输入第一行包含两个整数n、m(0<n,m<21)分别表示n行m列的矩阵，第二行是长度不超过100的单词W（在整个矩阵中给定单词W只会出现一次），从第3行到第n+2行是只包含大小写英文字母的长度为m的字符串矩阵。

输出描述:

如果能在矩阵中连成给定的单词，则输出给定单词首字母在矩阵中的位置（第几行 第几列），否则输出“NO”。

示例1
输入

5 5

HELLOWORLD

CPUCY

EKLQH

CHELL

LROWO

DGRBC

输出

3 2

示例2
输入

5 5

Helloworld

CPUCh

wolle

orldO

EKLQo

PGRBC

输出

NO

说明

区分大小写

解题思路
1、求出第一个字符的坐标（x，y），索引n为0

2、a）判断坐标的横坐标x是否大于0

                I.  如果x大于0，则向左一格（x-1，y）查找，如果此格字符等于n+1索引的字

                    符，求得此时字符坐标（x，y），将其坐标内容置空（防止后续查找重复数

                    据）并将其带入步骤2；

               Ⅱ. 如果x等于0（左边没有数据）或此格数据不等于n+1索引的字符，进入步

                      骤b

      b）判断坐标的横坐标x是否小于行数-1

                I.  如果小于，则向右一格（x+1，y）查找，如果此格字符等于n+1索引的字符，

                    求得此时字符坐标（x，y），将其坐标内容置空（防止后续查找重复数据）并

                    将其带入步骤2；

               Ⅱ. 如果x等于行数-1，右边没有数据，进入步骤,c

      c）判断坐标的纵坐标y是否大于0

                I.  如果大于0，则向上一格（x，y-1）查找，如果此格字符等于n+1索引的字

                   符，求得此时字符坐标（x，y），将其坐标内容置空（防止后续查找重复数

                   据）并将其带入步骤2；

              Ⅱ. 如果y等于0，上边没有数据，进入步骤d

      d）判断坐标的纵坐标y是否大于列数-1

                I.  如果小于列数-1，则向下一格（x，y+1）查找，如果此格字符等于n+1索引的

                    字符，求得此时字符坐标（x，y），将其坐标内容置空（防止后续查找重复

                    数据）并将其带入步骤2；

               Ⅱ. 如果y等于列数-1，下边没有数据

      注：每次循环索引n都需要递增，递归的边界就是n等于字符长度-1（索引从0开始）；

             如果无法正确查找到最后一个字符，则前面的置空都需要还原，以进行下次再次

             查找。

代码
let input = readLine().split(" ").map(Number);
//let input = "5 5".split(" ").map(Number);
 
var n = input[0];  //行
var m = input[1];  //列
var str = readLine();    //单词
//var str = "HELLOWORLD";
//let test = ["CPUCY","EKLQH","CHELL","LROWO","DGRBC"];
// var str = "Helloworld";
// let test = ["CPUCh","wolle","orldO","EKLQo","PGRBC"];
 
var len = str.length; //单词长度
let chars = [];
 
for(let i=0;i<n;i++){
    let input2 = readLine();
    //let input2 = test[i];
    chars[i] = [];
    for(let j=0;j<m;j++){
        chars[i][j] = input2.charAt(j);
    }
}
 
let res = "NO";
let start = str.charAt(0); //首字母
for(let i=0; i<n; i++){
    for(let j=0; j<m; j++){
        if(start == chars[i][j] && findNext(i, j,0, chars)==1){
            res = (i+1)+" "+(j+1);  //坐标需要再索引上+1
            break;
        }
    }
}
 
console.log(res);
    
 
function findNext( x, y, index, chars){
 
    if(index == len-1){ //所有字符都找到了
        return 1;
    }
    index++;
    let temp = str.charAt(index);
 
    if(x>0 && chars[x-1][y] == temp){   //向左一格
        chars[x-1][y] = 0;  //找过的就置为0，防止重复查找
        if(findNext(x-1, y, index, chars) == 1){
            return 1;
        }else {
            chars[x-1][y] = temp;   //如果不满足需要还原，否则会影响第二次查找
        }
    }
 
    if(x<n-1 && chars[x+1][y] == temp){ //向右一格
        chars[x+1][y] = 0;
        if(findNext(x+1, y, index, chars) == 1){
            return 1;
        }else {
            chars[x+1][y] = temp;
        }
    }
 
    if(y>0 && chars[x][y-1] == temp){   //向上一格
        chars[x][y-1] = 0;
        if(findNext(x,y-1, index, chars) == 1){
            return 1;
        }else {
            chars[x][y-1] = temp;
        }
    }
 
    if(y<m-1 && chars[x][y+1] == temp){ //向下一格
        chars[x][y+1] = 0;
        if(findNext(x,y+1, index, chars) == 1){
            return 1;
        }else {
            chars[x][y+1] = temp;
        }
    }
 
    return 0;
}

--------------------------
标题：找单词 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
给一个字符串和一个 二维字符数组 ，如果该字符串存在于该数组中，则按字符串的字符顺序输出字符串每个字符所在单元格的位置下标字符串，如果找不到返回字符串"N"。

1.需要按照字符串的字符组成顺序搜索，且搜索到的位置必须是相邻单元格，其中“相邻单元格”是指那些水平相邻或垂直相邻的单元格。

2.同一个单元格内的字母不允许被重复使用。

3.假定在数组中最多只存在一个可能的匹配。

输入描述:

1.第1行为一个数字（N）指示二维数组在后续输入所占的行数。

2.第2行到第N+1行输入为一个二维大写字符数组，每行字符用半角,分割。

3.第N+2行为待查找的字符串，由大写字符组成。

4.二维数组的大小为N*N，0<N<=100。

5. 单词长度 K，0<K<1000。

输出描述:

输出一个位置下标字符串，拼接格式为：第1个字符行下标+","+第1个字符列下标+","+第2个字符行下标+","+第2个字符列下标...+","+第N个字符行下标+","+第N个字符列下标

示例1
输入

4

A,C,C,F

C,D,E,D

B,E,S,S

F,E,C,A

ACCESS

输出

0,0,0,1,0,2,1,2,2,2,2,3

说明

ACCESS分别对应二维数组的[0,0]  [0,1] [0,2] [1,2] [2,2] [2,3]下标位置

代码
//var n = Number(readline());
var n = Number("4");
 
let test = ["A,C,C,F","C,D,E,D","B,E,S,S","F,E,C,A"];
let strings = [];
for(let i=0; i<n; i++){
    //let inputStrings = readline().split(",");
    let inputStrings = test[i].split(",");
    strings[i] = [];
    for(let j=0; j<n; j++){
        strings[i][j] = inputStrings[j];
    }
}
 
//var inputS = readline();
var inputS = "ACCESS";
var slen = inputS.length;
let first = inputS[0];//从第一个值开始
let isSuccess = false;
var res =  "";
 
for(let i=0; i<n; i++){
    for(let j=0; j<n; j++){
        if(strings[i][j] == first){
            let temp = copy(strings);    //对数组进行复制，否则影响第二次计算
            res = i + "," + j;
            temp[i][j] = ""; //已取出的值置空
            if(nextNum(0, i, j, temp)==1){ //表示已经成功取出数据
                isSuccess = true;
                console.log(res);
                break;
            }
        }
    }
    if(isSuccess){
        break;
    }
}
if(!isSuccess){
    console.log("N");
}
 
function copy( strings){
    let x = strings.length;
    let copyS = [];
 
    for ( let i=0; i<x; i++) {
        copyS[i] = [];
        for ( let j=0; j<x; j++) {
            copyS[i][j] = strings[i][j];
        }
    }
    return copyS;
}
 
function nextNum( index, row, col, temp){
 
    if(index == slen-1){  //递归到最后一位表示已经成功
        return 1;
    }
    index++;    //字符串下标
    let s= inputS[index];
 
    if(row>0 && temp[row-1][col] == s){    //对上边的字符串进行比较
        temp[row-1][col] = "";  //将已经取出的字符串进行置空，防止多次取值
        res += ","+ (row-1)+","+col;    //添加坐标
        if(nextNum(index, row-1, col, temp) == 1){ //值为1表示成功取出
            return 1;
        }else {
            res = res.substring(0,res.length-4);  //如果失败则进行还原
            temp[row-1][col] = s;
        }
    }
    if(col>0 && temp[row][col-1] == s){  // 左边
        temp[row][col-1] = "";
        res += ","+row+","+(col-1);
        if(nextNum(index, row, col-1, temp) == 1){
            return 1;
        }else {
            res = res.substring(0, res.length-4);
            temp[row][col-1] = s;
        }
    }
    if(row<n-1 && temp[row+1][col] == s){    //下边
        temp[row+1][col] = "";
        res += ","+(row+1)+","+col;
        if(nextNum(index, row+1, col, temp) == 1){
            return 1;
        }else {
            res = res.substring(0, res.length-4);
            temp[row+1][col] = s;
        }
    }
    if(col<n-1 && temp[row][col+1] == s){    //右边
        temp[row][col+1] = "";
        res += ","+row+","+(col+1);
        if(nextNum(index, row, col+1, temp) == 1){
            return 1;
        }else {
            res = res.substring(0, res.length-4);
            temp[row][col+1] = s;
        }
    }
 
    return 0;
}

--------------------------
标题：找城市 | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
一张地图上有n个城市，城市和城市之间有且只有一条道路相连：要么直接相连，要么通过其它城市中转相连（可中转一次或多次）。城市与城市之间的道路都不会成环。

当切断通往某个城市 i 的所有道路后，地图上将分为多个连通的城市群，设该城市 i 的聚集度为 DPi （Degree of Polymerization）,  DPi = max(城市群1的城市个数， 城市群2的城市个数, ... 城市群m的城市个数)。

请找出地图上 DP 值最小的城市（即找到城市 j，使得 DPj = min(DP1, DP2 ... DPn) )

提示：如果有多个城市都满足条件，这些城市都要找出来（可能存在多个解）

提示：DPi 的计算，可以理解为已知一棵树，删除某个节点后，生成的多个子树，求解多个子树节点数的问题。

输入描述:

每个样例：第一行有一个整数N，表示有N个节点。1<=N<=1000

接下来的N-1行每行有两个整数x,y，表示城市x与城市y连接。1<=x, y<=N

输出描述:

输出城市的编号。如果有多个，按照编号升序输出。

示例1
输入

5

1 2

2 3

3 4

4 5

输出

3

说明

输入表示的是如下地图：



对于城市3，切断通往3的所有道路后，形成2个城市群[（1,2）,（4,5）]，其聚集度分别都是2。DP3 = 2。 对于城市4，切断通往城市4的所有道路后， 形成2个城市群[ (1,2,3), (5) ]，DP4 = max（3, 1）= 3 。依次类推，切断其它城市的所有道路后，得到的DP都会大于2，因为城市3就是满足条件的城市，输出是3。

示例2
输入

6

1 2

2 3

2 5

3 4

3 6

输出

2 3

说明

输入表示的是如下地图：



切断通往2的所有道路后，形成3个城市群[（1）,（5），（3,4,6）]，其聚集度分别都是1、1、3，因此DP2 = 3。

切断通往3的所有道路后，形成3个城市群[（1，2,5）,（4），（,6）]，其聚集度分别都是3、1、1，因此DP3 = 3。

切断其它城市的所有道路后，得到的DP都会大于3，因为城市2、3就是满足条件的城市， 升序排列 输出是2 3

解题思路
遍历删除城市及其城市对，求出剩下的城市及其最大城市群作为他的聚集度，最后求出最小聚集度的城市

如例1

5    【1 2，2 3，3 4，4 5】

删除城市1：城市对【2 3，3 4，4 5】，【（2,3,4,5）】，聚集度为4，DP1=4

删除城市2：城市对【3 4，4 5】，【（1），（3,4,5）】，聚集度为3，DP2=3

删除城市3：城市对【1 2，4 5】，【（1,2），（4,5）】，聚集度为2，DP3=2

删除城市4：城市对【1 2，2 3】，【（1,2,3），（5）】，聚集度为3，DP4=3

删除城市5：城市对【1 2，2 3，3 4】，【（1,2,3,4）】，聚集度为4，DP5=4

最小聚集度为2，城市3

代码
let n = Number(readline());
//let n = Number("6");
let connectList = [];    //城市连通对集合
 
//let test = ["1 2","2 3","2 5","3 4","3 6"];
 
for(let i=0; i<n-1; i++){
    let tempList = readline().split(" ").map(Number);
    //let tempList = test[i].split(" ").map(Number);
    connectList.push(tempList);
}
 
let map = new Map(); //城市跟其聚集度的键值对
var cityGroup;
 
for(let i=0; i<n; i++){
    let temp = [];   //去掉某个城市后的城市连通对集合
 
    for(let j=0; j<n-1; j++){
        if(!connectList[j].includes(i+1)){
            temp.push(connectList[j]);
        }
    }
 
    cityGroup = [];    //城市群集合
    if(temp.length == 0){
        cityGroup.push(1); //如果去掉的城市跟所有城市都相通，则聚集度为1
    }else {
        getCityGroup(temp, new Set());
    }
 
    cityGroup.sort((a,b)=>{return b-a});  //对城市群进行排序
    map.set(i+1, cityGroup[0]);    //最大的城市群则为聚集度
}
 
let mapList = Array.from(map);
 
mapList.sort((a,b)=>{
    return a[1]-b[1];
});
 
let min = mapList[0][1]; //找出聚集度最小值
let res = "";
for (let i=0; i<n; i++){
    let m = mapList[i];
    if(m[1]== min){
        res += m[0] + " ";
    }else {
        break;
    }
}
 
console.log(res.substring(0, res.length-1));
 
/**
 *
 * @param cityConnectList 城市连通对集合
 * @param cityList  相互连通的城市
 */
function getCityGroup( cityConnectList, cityList){
 
    for(let i=0; i<cityConnectList.length; i++){
 
        let a = cityConnectList[i][0];  //a城市
        let b = cityConnectList[i][1];  //b城市
 
        if(cityList.size == 0){   //初始化直接加入a和b，不需要进行判断
 
            cityList.add(a);
            cityList.add(b);
            cityConnectList.splice(i, 1);  //已加入的城市需要剔除
 
            if(cityConnectList.length == 0){  //集合中没有数据了，说明互相连通城市已处理完毕
                cityGroup.push(cityList.size);
            }
 
            getCityGroup(cityConnectList, cityList);
        }else if(cityList.has(a) || cityList.has(b)){
 
            cityList.add(a);
            cityList.add(b);
            cityConnectList.splice(i, 1);
 
            if(cityConnectList.length==0){
                cityGroup.push(cityList.size);
            }
 
            getCityGroup(cityConnectList, cityList);
        }else if(i==cityConnectList.length-1){
 
            cityGroup.push(cityList.size);
 
            getCityGroup(cityConnectList, new Set());
        }
    }
}

--------------------------
标题：找最小数 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
给一个正整数NUM1，计算出新正整数NUM2，NUM2为NUM1中移除N位数字后的结果，需要使得NUM2的值最小。

输入描述:

1.输入的第一行为一个 字符串 ，字符串由0-9字符组成，记录正整数NUM1，NUM1长度小于32。

2.输入的第二行为需要移除的数字的个数，小于NUM1长度。

如：

2615371
4

输出描述:

输出一个数字字符串，记录最小值NUM2。

如：131

示例1
输入

2615371

4

输出

131

说明

移除2、6、5、7这四个数字，剩下1、3、1按原有顺序排列组成131，为最小值

解题思路
1、根据题意，获取的最后值为原长度-需要移除的长度

2、因为是移除，所以数字的位置不能有所改变。

3、要最小数则前面的数要尽量的小

注：题意没有明确表示第一位不能为0，需要注意一下

如例一所示：

最后值 3（7-4） 位数

a、第一位数在前5位数种找最小值1，位置是3

b、第二位数在第3位数到第6位数找最小值3，位置是5

c、第三位数在第6位数到第7位数找最小值1

所以最后的值131

代码
let  s = readLine();
let m = Number(readLine());
// let  s = "2615371";
// let m = Number("4");
 
let l = m+1;        //截取字符的右边界
let index = 0;
let res = "";
 
while (res.length<s.length-m){
 
    let str = s.substring(index,l);        //求出第一个数字的最小值
    let min = Number.MAX_VALUE;
    let len = str.length;
    let ints = [];
    for(let i=0;i<len;i++){
        let temp = str.charAt(i);   //char转换成int
        ints[i] = temp; //放入数组求出下标
        if(res=="" && temp==0){ //第一位不能为0（如没有要求可以删掉）
            continue;
        }
        min = Math.min(min,temp);
    }
    res += String(min);
 
    for(let i=0;i<len;i++){
        if(ints[i] == min){
            index += i;      //求出第一个最小值的下标然后去截取循环获取最小值
            break;
        }
    }
    index++;
    l++;//数字要往后移一位
 
}
 
console.log(res);

--------------------------
标题：找朋友 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
在学校中，N个小朋友站成一队， 第i个小朋友的身高为height[i]，

第i个小朋友可以看到的第一个比自己身高更高的小朋友j，那么j是i的好朋友(要求j > i)。

请重新生成一个列表，对应位置的输出是每个小朋友的好朋友位置，如果没有看到好朋友，请在该位置用0代替。

小朋友人数范围是 [0, 40000]。

输入描述:

第一行输入N，N表示有N个小朋友

第二行输入N个小朋友的身高height[i]，都是整数

输出描述:

输出N个小朋友的好朋友的位置

示例1
输入

2

100 95

输出

0 0

说明

第一个小朋友身高100，站在队尾位置，向队首看，没有比他身高高的小朋友，所以输出第一个值为0。
第二个小朋友站在队首，前面也没有比他身高高的小朋友，所以输出第二个值为0。

示例2
输入

8

123 124 125 121 119 122 126 123

输出

1 2 6 5 5 6 0 0

说明

123的好朋友是1位置上的124

124的好朋友是2位置上的125

125的好朋友是6位置上的126

以此类推

解题思路
从第一个小朋友开始遍历，每个小朋友都从前一个小朋友开始向前遍历寻找比自己高的小朋友，找到则输出其位置，进入下一个小朋友的遍历，否则用0代替，接着进入下一个小朋友的遍历

代码
let n = Number(readLine());
let ints = readLine().split(" ").map(i=>parseInt(i));
// let n = Number("8");
// let ints = "123 124 125 121 119 122 126 123".split(" ").map(i=>parseInt(i));
 
let list = [];
 
for(let i=0;i<n-1;i++){ //最后一个直接跳过
    for(let j=i+1;j<n;j++){
        if(ints[j]>ints[i]){
            list.push(j);
            break;
        }
        if(j==n-1){    //到最后一位都没有符合的
            list.push(0);
        }
    }
}
list.push(0);    //最后一位小朋友
console.log(list.join(" "));

--------------------------
标题：找终点 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一个正整数数组，设为nums，最大为100个成员，求从第一个成员开始，正好走到数组最后一个成员，所使用的最少步骤数。

要求：

1、第一步必须从第一元素开始，且1<=第一步的步长<len/2;（len为数组的长度，需要自行解析）。

2、从第二步开始，只能以所在成员的数字走相应的步数，不能多也不能少, 如果目标不可达返回-1，只输出最少的步骤数量。

3、只能向数组的尾部走，不能往回走。

输入描述:

由正整数组成的数组，以空格分隔，数组长度小于100，请自行解析数据数量。

输出描述:

正整数，表示最少的步数，如果不存在输出-1

示例1
输入

7 5 9 4 2 6 8 3 5 4 3 9

输出

2

说明

第一步： 第一个可选步长选择2，从第一个成员7开始走2步，到达9；第二步： 从9开始，经过自身数字9对应的9个成员到最后。

示例2
输入

1 2 3 7 1 5 9 3 2 1

输出

-1

解题思路
根据题意，第一步可以是 中位数 之前的任意一个数；所以遍历中位数之前的数，模拟对应的步数向前前行，求出能到达终点的步数最大值。

代码
let nums = readLine().split(" ").map(i=>parseInt(i));
//let nums = "7 5 9 4 2 6 8 3 5 4 3 9".split(" ").map(i=>parseInt(i));
 
let ints = [];
let len = nums.length;
 
for(let i=0;i<len;i++){
    ints[i] = nums[i];
}
 
let step = 0;   //步数的进度（数组下标）
let count = 0;  //步数
let x = Number.MAX_VALUE;
for(let i=0;i<len/2-1;i++){ //从第一个元素开始，第一步<length/2(下标为0，所以要减一)
    step = i;
    count = 1;
    while (step < len-1) {  //没有走完就需要继续
        step += ints[step];
        count++;
    }
    if(step == len-1){  //正好走完，比较步数
        x = Math.min(x,count);
    }
}
if(x==Number.MAX_VALUE){
    console.log("-1");
}else {
    console.log(x);
}

--------------------------
标题：找车位 | 时间限制：1秒 | 内存 限制：32768K | 语言限制：不限
停车场有一横排车位，0代表没有停车，1代表有车。至少停了一辆车在车位上，也至少有一个空位没有停车。

为了防剐蹭，需为停车人找到一个车位，使得距停车人的车最近的车辆的距离是最大的，返回此时的最大距离。

输入描述:

1、一个用半角逗号分割的停车标识字符串，停车标识为0或1，0为空位，1为已停车。

2、停车位最多100个。

输出描述:

输出一个整数记录最大距离。

示例1
输入

1,0,0,0,0,1,0,0,1,0,1

输出

2

说明

当车停在第3个位置上时，离其最近的的车距离为2（1到3）。
当车停在第4个位置上时，离其最近的的车距离为2（4到6）。
其他位置距离为1。
因此最大距离为2。

解题思路
求最大距离，就是求连续0的最大长度。

如果是偶数直接除以2；如果是奇数则+1除以2。

*难点是要考虑到前后为0的情形，这两种情形是不需要进行除法的。

代码
let s = readLine().split(",");
//let s = "0,0,0,0,0,1,0,0,1,0,1".split(",")
 
let list = [];
 
for(let i=0;i<s.length;i++){
    if(s[i] == "1"){
        list.push(i);    //记录1的下标，0的长度=后一个下标 - 前一个下标 - 1
    }
}
 
let maxFE = 0;
if(s[0] == "0"){   //考虑到开头为0的情形
    maxFE = Math.max(maxFE,list[0]);
}
if(s[s.length-1] == "0"){  //考虑到末尾为0的情形
    maxFE = Math.max(maxFE,s.length-1-list[list.length-1]);
}
 
let max = 0;
 
for(let i=1;i<list.length;i++){
    max = Math.max(max,list[i]-list[i-1]-1);    //通过1的下标求0的长度
}
 
if(max%2==0){
    console.log(Math.max(maxFE,max/2));  //偶数直接除以2
}else {
    console.log(Math.max(maxFE,(max+1)/2));  //奇数+1除以2
}

--------------------------
标题： 报数 游戏 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
100个人围成一圈，每个人有一个编码，编号从1开始到100。他们从1开始依次报数，报到为M的人自动退出圈圈，然后下一个人接着从1开始报数，直到剩余的人数小于M。请问最后剩余的人在原先的编号为多少？

输入描述:

输入一个整数参数M

输出描述:

如果输入参数M小于等于1或者大于等于100，输出“ERROR!”；否则按照原先的编号从小到大的顺序，以英文逗号分割输出编号字符串

示例1
输入

3

输出

58,91

说明

输入M为3，最后剩下两个人

示例2
输入

4

输出

34,45,97

说明

输入M为4，最后剩下三个人

解题思路
新建一个从1到100的集合。下标0-99（假设M=3）

1、2、3、4、5、6、7、8、9、10……….100

从1开始报数，剔除3（下标2【M-1】）：

1、2、4、5、6、7、8、9、10……….100

从4开始报数，则剔除6（下标为4【2（上个删除的下标）+3（M）-1】）：

1、2、4、5、7、8、9、10……….100

从7开始报数，则剔除9（下标6【4（上个删除的下标）+3（M）-1】）

以此类推。。。

当删除99时，从100开始报数，因为是一个圆圈，所以剔除2，此时下标为1：

上个删除下标为（上个删除的下标【33*2】+3（M）-1-人数总和（100-33））

重复上面操作，当人数<M的时候 跳出循环

代码
let n = Number(readLine());
 
//let n = Number("3");
 
let list = [];
 
for(let i=1;i<=100;i++){
    list.push(i);    //100个人的集合
}
 
let i=n-1;  //初始下标（集合下标从0开始，所有要-1）
 
while (list.length>=n){ //如果人数大于等于n就需要继续
        list.splice(i,1); //移除报n的人
        i--;    //因为少了一个人所以后面的所有下标都要向前移一位
        i = i+n<list.length ? i+n : i+n-list.length;  //因为是围成的圆圈，所以下标越界后需要绕到最前面
}
 
console.log(list);

--------------------------
标题：拼接URL | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
给定一个URL前缀和URL后缀，通过","分割，需要将其连接为一个完整的URL，如果前缀结尾和后缀开头都没有“/”，需自动补上“/”连接符，如果前缀结尾和后缀开头都为“/”，需自动去重。

约束：不用考虑前后缀URL不合法情况。

输入描述:

URL前缀（一个长度小于100的字符串),URL后缀（一个长度小于100的字符串）。

输出描述:

拼接后的URL。

示例1
输入

/ acm ,/bb

输出

/acm/bb

示例2
输入

/abc/,/ bcd

输出

/abc/bcd

示例3
输入

/acd,bef

输出

/acd/bef

示例4
输入

,

输出

/

解题思路
将字符串中的“/”去掉，然后进行拼接

代码
let s = readLine().split(",");
//let s = ",/abc".split(",");
 
let res = "";
 
for(let i=0;i<s.length;i++){
    if(s[i]!="" && s[i]!="/"){
        /**
        * 将字符串中的"/"直接去除
        */
        res+="/"+s[i].replace("/","");
    }
}
 
console.log(res=="" ? "/" : res);

--------------------------
标题：按身高和体重排队 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
某学校举行运动会，学生们按编号(1、2、3…n)进行标识，现需要按照身高由低到高排列，对身高相同的人，按体重由轻到重排列；对于身高体重都相同的人，维持原有的编号顺序关系。请输出排列后的学生编号。

输入描述:

两个序列，每个序列由n个正整数组成（0 < n <= 100）。第一个序列中的数值代表身高，第二个序列中的数值代表体重。

输出描述:

排列结果，每个数值都是原始序列中的学生编号，编号从1开始

示例1
输入

4

100 100 120 130

40 30 60 50

输出

2 1 3 4

说明

输出的第一个数字2表示此人原始编号为2，即身高为100，体重为30的这个人。由于他和编号为1的人身高一样，但体重更轻，因此要排在1前面。

示例2
输入

3

90 110 90

45 60 45

输出

1 3 2

说明

1和3的身高体重都相同，需要按照原有位置关系让1排在3前面，而不是3 1 2

解题思路
1、给每位学生都编上号，并将其编号、身高和体重放入集合中

2、通过集合的sort方法对其体重和身高进行排序

3、遍历步骤2获取的集合，求出其编号排序

代码
let n = Number(readLine());
let h = readLine().split(" ").map(i=>parseInt(i));   //身高数组
let w = readLine().split(" ").map(i=>parseInt(i));    //体重数组
// let n = Number("3");
// let h = "90 110 90".split(" ").map(i=>parseInt(i));   //身高数组
// let w = "45 60 45".split(" ").map(i=>parseInt(i));    //体重数组
 
let lists = [];
 
for (let i=0;i<n;i++){
    let stu = [];  //学生数组
    stu.push(i+1);   //学生序号
    stu.push(h[i]);
    stu.push(w[i]);
    lists.push(stu);
}
 
lists.sort((a,b)=>{
    if(b[1]< a[1]){  //通过身高升序排序
        return 1;
    }else if(b[1]==a[1]){   //如果升高相同
        if(b[2]>a[2]){  //通过体重升序排序
            return -1;
        }else {
            return 1;
        }
    }else {
        return -1;
    }
});
 
let res = "";
 
for(let i=0;i<lists.length;i++){
    res += lists[i][0]; //获取学生序号排序
    if(i!=lists.length-1){
        res+=" ";
    }
}
 
console.log(res);

--------------------------
标题：敏感字段加密 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一个由多个命令字组成的命令字符串：

1、字符串长度小于等于127字节，只包含大小写字母，数字，下划线和偶数个双引号；
2、命令字之间以一个或多个下划线_进行分割；
3、可以通过两个双引号""来标识包含下划线_的命令字或空命令字（仅包含两个双引号的命令字），双引号不会在命令字内部出现；
请对指定索引的敏感字段进行加密，替换为******（6个*），并删除命令字前后多余的下划线_。如果无法找到指定索引的命令字， 输出字符串 ERROR。

输入描述:

输入为两行，第一行为命令字索引K（从0开始），第二行为命令字符串S。

输出描述:

输出处理后的命令字符串，如果无法找到指定索引的命令字，输出字符串ERROR

示例1
输入

1

password__a12345678_timeout_100

输出

password_******_timeout_100

示例2
输入

2

aaa_password_"a12_45678"_timeout__100_""_

输出

aaa_password_******_timeout_100_""

解题思路
1、 遍历字符串 ，未出现下划线，则直接进行字符串拼接

2、出现下划线则判断是否在引号内，如果在引号内，则继续拼接字符串；如果不在引号内，则截取字符串放入集合中

3、根据输入的索引，对集合中的字符串进行拼接。

代码
let n = Number(readLine());
let s = readLine();
// let n = Number("2");
// let s = 'aaa_password_"a12_45678"_timeout__100_""_';
 
let len = s.length;
let list = [];
let temp = "";
let yh = false; //是否有引号
 
for(let i=0; i<len; i++){
    if(s.charAt(i)!='_'){
        if(s.charAt(i)=='\"'){
            yh = !yh;
        }
        temp += s.charAt(i);  //非下划线直接拼接字符
        if(i==len-1){
            list.push(temp); //最后一位直接push
        }
    }else {
        if(temp==""){
            continue;   //字符串为空则进入下个循环
        }
        if(yh){
            temp+=s.charAt(i);  //引号内的下划线直接拼接字符串
        }else {
            list.push(temp); //push字符串
            temp = "";  //置空为下次使用
        }
    }
}
 
let count = list.length;
 
if(n>=count){
    console.log("ERROR");
}else {
    let res = "";
    for(let i=0; i<count; i++){
        if(i==n){
            res+="******";  //对应下标的字符串进行加密
        }else {
            res += list[i];   //拼接字符串
        }
        if(i != list.length-1){
            res += "_";   //非最后一个后面需要加下划线
        }
    }
    console.log(res);
}

--------------------------
标题：数列描述 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
有一个数列a[N] (N=60)，从a[0]开始，每一项都是一个数字。数列中a[n+1]都是a[n]的描述。其中a[0]=1。

规则如下：

a[0]:1

a[1]:11(含义：其前一项a[0]=1是1个1，即“11”。表示a[0]从左到右，连续出现了1次“1”）

a[2]:21(含义：其前一项a[1]=11，从左到右：是由两个1组成，即“21”。表示a[1]从左到右，连续出现了两次“1”)

a[3]:1211(含义：其前一项a[2]=21，从左到右：是由一个2和一个1组成，即“1211”。表示a[2]从左到右，连续出现了1次“2”，然后又连续出现了1次“1”)

a[4]:111221(含义：其前一项a[3]=1211，从左到右：是由一个1、一个2、两个1组成，即“111221”。表示a[3]从左到右，连续出现了1次“1”，连续出现了1次“2”，连续出现了两次“1”)

请输出这个数列的第n项结果（a[n]，0≤n≤59）。

输入描述:

数列的第n项(0≤n≤59)：
4

输出描述:

数列的内容：
111221

示例1
输入

4

输出

111221

解题思路
看到这种找规律的题目，基本就要想到递归。

注：因为规则是观察连续数出现次数，所以需要对字符串进行前后字符比较，而当n=1的时候只有一位，无法进行比较操作，我们就可以将其单拎出来。将n=2作为递归边界条件。

代码
let n = Number(readLine());
//let n = Number("4");
 
console.log(n==0 ? "1" : getRes(n));
 
function getRes(n){
 
    if(n==1){
        return "11";  //因为当n=0的时候只有一位数，无法进行比较
    }
    let s = getRes(n-1);
    let len = s.length;
    let sb = "";
    let count = 1;  //连续相同数字的计数
    for(let i=1;i<len;i++){
        if(s.charAt(i)==s.charAt(i-1)){
            count++;    //数字相同且连续则+1
        }else {
            sb += count;
            sb += s.charAt(i-1);
            count=1;    //重置下计数
        }
        if(i==len-1){   //最后一位
            sb += count;
            sb += s.charAt(i);
        }
    }
    return sb;
}

--------------------------
标题：数字反转打印 | 时间限制：1秒 | 内存限制：262144K | 语言不限
小华是个很有对数字很敏感的小朋友，他觉得数字的不同排列方式有特殊美感。某天，小华突发奇想，如果数字多行排列，第一行1个数，第二行2个，第三行3个，即第n行有n个数字，并且奇数行正序排列，偶数行 逆序 排列，数字依次累加。这样排列的数字一定很有意思。聪明的你能编写代码帮助小华完成这个想法吗？

规则总结如下：

a、每个数字占据4个位置，不足四位用‘*’补位，如1打印为1***。

b、数字之间相邻4空格。

c、数字的打印顺序按照正序逆序交替打印,奇数行正序，偶数行逆序。

d、最后一行数字顶格，第n-1行相对第n行缩进四个空格

输入描述:

第一行输入为N，表示打印多少行; 1<=N<=30

输入：2

输出描述:

XXXX1***

3***XXXX2***

示例1
输入

2

输出

    1***

3***    2***

备注:

符号*表示，数字不满4位时的补位，符号X表示数字之间的空格。注意实际编码时不需要打印X，直接打印空格即可。此处为说明题意，故此加上X

解题思路
根据题目所示，得出的数据应该如下图所示：

            1***

        3***    2***

    4***    5***    6***

10**    9***    8***    7***

........................................

从上图可以得到规律：

第n行的最小数字 = 第n-1行的最小数字+第n-1行的行数（n-1）

得到n行的最小数字之后再通过n次递增，就会获取n行的所有数字

1、每加一行，前面的所有行都要加上四个空格

2、每个数字占位4格，那我们将每个数字拼接3个*，最后截取前四位

3、先将数字按正序排序，在偶数行进行反转

代码
let n = Number(readLine());
//let n = Number("30");
 
let lists = []; //总集合
 
for(let i=1;i<=n;i++){      //为了方便i初始值设为1
 
    let list = [];  //每一行的数据（不使用字符串，是方便后续反转）
    let fn = firstNum(i);     //先计算出行头数字
 
    lists.forEach(x=>{
        x.unshift("    ");        //每加一行，前面的所有行前面都加一个"    "
    });
 
    for(let j=0;j<i;j++){
        let temp = fn++ + "***";        //每个数后面都加三个*，因为至少一位数，所以只要加三个
        list.push(temp.substring(0,4));     //头数向后递加，只取前面四个字符串
        if(j!=i-1){
            list.push("    ");       //除了最后一个数，其余全部加上"    "
        }
    }
 
    if(i%2==0){
        list.reverse();      //偶数行进行翻转
    }
 
    lists.push(list);
}
 
lists.forEach(x=>{
    let res = "";        //把所有行转化成字符串类型
    for(let i=0;i<x.length;i++){
        res+=x[i];
    }
    console.log(res);
});
 
 
function firstNum(n){
    if(n == 1){
        return 1;
    }
    return firstNum(n-1) + n - 1;       //根据规律推出第n行的头为n-1的头加上n-1
}

--------------------------
标题：数字涂色 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
疫情过后，希望小学终于又重新开学了，三年二班开学第一天的任务是将后面的黑板报重新制作。黑板上已经写上了N个正整数，同学们需要给这每个数分别上一种颜色。为了让黑板报既美观又有学习意义，老师要求同种颜色的所有数都可以被这种颜色中最小的那个数整除。现在请你帮帮小朋友们，算算最少需要多少种颜色才能给这N个数进行上色。

输入描述:

第一行有一个正整数N，其中1 \leq N \leq 1001≤N≤100。

第二行有N个int型数(保证输入数据在[1,100]范围中)，表示黑板上各个正整数的值。

输出描述:

输出只有一个整数，为最少需要的颜色种数。

示例1
输入

3

2 4 6

输出

1

说明

所有数都能被2整除

示例2
输入

4

2 3 4 9

输出

2

说明

2与4涂一种颜色，4能被2整除；3与9涂另一种颜色，9能被3整除。不能4个数涂同一个颜色，因为3与9不能被2整除。所以最少的颜色是两种。

解题思路
1、对输入的数字集合进行升序排序。

2、将步骤1中索引为0的数字作为最小整数， 遍历集合 ，找出所有能整除最小整数的数字

3、从集合中剔除步骤2中获取的所有数字，重复步骤2，直至集合长度为0

代码
let n = Number(readLine());
let numList = readLine().split(" ").map(Number);  //输入数字集合
// let n = Number(4);
// let numList = "4 3 9 6".split(" ").map(Number);  //输入数字集合
 
let delList = [];  //已经涂色的集合
let res = 0;
 
numList.sort((a,b)=>{return a-b});  //对输入数字进行排序，方便找到最小值
 
while (numList.length!=0){
 
    let m = numList[0]; //取出最小值
    numList.splice(0,1);  //取出的数进行剔除
 
    for(let i=0;i<numList.length;i++){
        let temp = numList[i];
        if(temp%m==0){
            delList.push(temp);  //进行涂色
        }
    }
 
    res++;
    numList = numList.filter((v)=> !delList.includes(v)); //剔除已经涂色的数字
}
 
console.log(res);

--------------------------
标题：数组 二叉树  | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
二叉树也可以用数组来存储，给定一个数组，树的根节点的值存储在下标1，对于存储在下标N的节点，它的左子节点和右子节点分别存储在下标2*N和2*N+1，并且我们用值-1代表一个节点为空。
给定一个数组存储的二叉树，试求从根节点到最小的 叶子节点 的路径，路径由节点的值组成。

输入描述:

输入一行为数组的内容，数组的每个元素都是正整数或表示节点为空的-1，元素间用空格分隔。注意第一个元素即为根节点的值，即数组的第N个元素对应下标N，下标0在树的表示中没有使用，所以我们省略了。输入的树最多为7层。

输出描述:

输出从根节点到最小叶子节点的路径上，各个节点的值，由空格分隔，用例保证最小叶子节点只有一个。

示例1
输入

3 5 7 -1 -1 2 4

输出

3 7 2

说明

数组存储的二叉树如图，故到最小叶子节点的路径为3 7 2



 

示例2
输入

5 9 8 -1 -1 7 -1 -1 -1 -1 -1 6

输出

5 8 7 6

说明

数组存储的二叉树如图，故到最小叶子节点的路径为10 8 7 6，注意数组仅存储至最后一个非空节点，故不包含节点“7”右子节点的-1



 解题思路
父节点在数组中的索引为i，则其左子节点的索引为（i+1）*2-1，其右子节点索引为（i+1）*2

1、按照上述规律，遍历数组求出最小叶子节点的索引

2、步骤1求出的索引根据规律往上推出所有父节点

注：叶子节点是表示没有子节点的节点

代码
let ints = readLine().split(" ").map(Number);
//let ints = "3 5 7 -1 -1 2 4".split(" ").map(Number);
 
let len = ints.length;
let idx = -1;   //最小叶子节点索引
 
for (let i = 0; i < len; i++) {
    if (ints[i] == -1) {    //空节点直接返回
        continue;
    }
    if ( (i+1)*2+1 > ints.length ||
            (ints[(i+1)*2-1] == -1 && ints[(i+1)*2] == -1)) {  //判断是否为叶子节点
        if (idx == -1 || ints[idx] > ints[i]) {
            idx = i;
        }
    }
}
 
let stack = [];  //使用栈先进先出
stack.push(idx);
 
//用叶子节点向上推到根节点
while (idx>0) {
    if ((idx+1)%2 == 0) {
        idx = (idx+1)/2 - 1;
        stack.push(idx);
    } else {
        idx = idx/2 - 1;
        stack.push(idx);
    }
}
 
let ret = "";
while (stack.length!=0) {
    ret += " " + ints[stack.pop()];
}
 
console.log(ret.substring(1));

--------------------------
标题：数组去重和排序 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一个乱序的数组，删除所有的重复元素，使得每个元素只出现一次，并且按照出现的次数从高到低进行排序，相同出现次数按照第一次出现顺序进行先后排序。

输入描述:

一个数组

输出描述:

去 重排序 后的数组

示例1
输入

1,3,3,3,2,4,4,4,5

输出

3,4,1,2,5

备注:

数组大小不超过100

数组元素值大小不超过100

代码
let s = readLine().split(",").map(i=>parseInt(i));
//let s = "1,3,3,3,2,4,4,4,5".split(",").map(i=>parseInt(i));
 
let list = [];
 
for(let i=0;i<s.length;i++){
    let n = s[i];
    let isContain = false;
    for(let m of list){
        if(m.num==n){
            m.count++;
            isContain = true;
            break;
        }
    }
    if(!isContain){
        list.push({num:n,count:1}); //num：数字，count：出现次数
    }
}
 
list.sort((a,b)=>{
    if(b.count<a.count){  //次数降序排序
        return -1;
    }
    return 1;
});
 
let res = "";
for(let i=0;i<list.length;i++){
    res += list[i].num;
    if(i!=list.length-1){
        res+=",";
    }
}
 
console.log(res);

--------------------------
标题：数组拼接 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
现在有多组整数 数组 ，需要将它们合并成一个新的数组。合并规则，从每个数组里按顺序取出固定长度的内容合并到新的数组中，取完的内容会删除掉，如果该行不足固定长度或者已经为空，则直接取出剩余部分的内容放到新的数组中，继续下一行。

输入描述:

第一行是每次读取的固定长度，0<长度<10
第二行是整数数组的数目，0<数目<1000
第3-n行是需要合并的数组，不同的数组用回车换行分隔，数组内部用逗号分隔，最大不超过100个元素。

输出描述:

输出一个新的数组，用逗号分隔。

示例1
输入

3

2

2,5,6,7,9,5,7

1,7,4,3,4

输出

2,5,6,1,7,4,7,9,5,3,4,7

说明

1、获得长度3和数组数目2。

2、先遍历第一行，获得2,5,6；

3、再遍历第二行，获得1,7,4；

4、再循环回到第一行，获得7,9,5；

5、再遍历第二行，获得3,4；

6、再回到第一行，获得7，按顺序拼接成最终结果。

示例2
输入

4

3

1,2,3,4,5,6

1,2,3

1,2,3,4

输出

1,2,3,4,1,2,3,1,2,3,4,5,6

代码
// let step = Number(readline());
// let m = Number(readline());
let step = Number("3");
let m = Number("2");
let test = ["2,5,6,7,9,5,7","1,7,4,3,4"];
let lists = [];
 
for(let i=0; i<m; i++){
    //let strings = readline().split(",").map(Number);
    let strings = test[i].split(",").map(Number);
    lists.push(strings);  //将数组放入集合中
}
 
let res = "";
let n = 0;  //起始下标
let count = 0;  //取完数字的数组
while (count<m){    //当取完的数组数量小于m时进入循环
    for(let i=0; i<m; i++){
        let list = lists[i];
        if(n>list.length){  //当其实下标大于数组长度时退出本次循环
            continue;
        }
        let end = n + step; //结束位置下标
        if(end >= list.length){   //当结束位置下标大于等于数组长度时
            end = list.length;
            count++;    //取完数字数组数量+1
        }
        for(let j=n; j<end; j++){
            res += list[j] + ",";
        }
    }
    n+=step;    //起始位置下标变更（+step）
}
 
console.log(res.substring(0,res.length-1));

--------------------------
标题：数组组成的最小数字 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一个整型数组，请从该数组中选择3个元素组成最小数字并输出（如果数组长度小于3，则选择数组中所有元素来组成最小数字）。

输入描述:

一行用半角逗号分割的字符串记录的整型数组，0 < 数组长度 <= 100，0 < 整数的取值范围 <= 10000。

输出描述:

由3个元素组成的最小数字，如果数组长度小于3，则选择数组中所有元素来组成最小数字。

示例1
输入

21,30,62,5,31

输出

21305

说明

数组长度超过3，需要选3个元素组成最小数字，21305由21,30,5三个元素组成的数字，为所有组合中最小的数字

示例2
输入

5,21

输出

215

说明

数组长度小于3， 选择所有元素来主城最小值，215为最小值。

解题思路
1、因为是要获取最小值，所以组成数字的元素越小越好，这样只要获取到数组中最小的三个数进行组合。

2、对取出来的数字进行 全排列 ，取其中最小值

（例：5，21，30——>52130，53021，21530，21305，30521，30215）

代码
let nums = readLine().split(",").map(i=>parseInt(i));
// let nums = "21,30,62,5,31".split(",").map(Number);
// let nums = "5,22,221".split(",").map(i=>parseInt(i));
 
let slen = nums.length;
let res = "";
var min = Number.MAX_VALUE;
 
if(slen==1){    //考虑到只有一个数的情况
    res = nums[0];
}else {
    let numList = [];
 
    for(let i=0;i<slen;i++){
        numList.push(nums[i]);
    }
 
    numList.sort((a,b)=>{return a-b});  //对数组进行排序
    let numsLen;
    if(slen==2){    //区别只有两个数的情况
        numsLen = 2;
    }else {
        numsLen = 3;
    }
 
    let ints = [];
    for(let i=0; i<numsLen; i++){
        ints[i] = numList[i];
    }
    fullArr(ints, 0, numsLen);   //对数字进行全排列找出最小值
 
    res = min;
}
console.log(res);
 
/**
 * 对ints中的数字进行全排列
 * @param ints
 * @param cursor
 * @param end
 */
function fullArr( ints, cursor, end){
 
    if(cursor == end){
        let s="";
        for(let i of ints){
            s+=i;
        }
        min = Math.min( min, Number(s));
    }else {
        for(let i=cursor; i<end; i++){
            swap(ints, cursor, i);
            fullArr(ints, cursor+1, end);
            swap(ints, cursor, i);
        }
    }
}
 
function swap( ints, a, b){
 
    let temp = ints[a];
    ints[a] = ints[b];
    ints[b] = temp;
 
}

--------------------------
标题： 数组 连续和 | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
给定一个含有N个正整数的数组, 求出有多少个连续区间（包括单个正整数）, 它们的和大于等于x。

输入描述:

第一行两个整数N x（0 < N <= 100000, 0 <= x <= 10000000)

第二行有N个正整数（每个正整数小于等于100)。

输出描述:

输出一个整数，表示所求的个数。

示例1
输入

3 7

3 4 7

输出

4

说明

3+4 4+7 3+4+7 7这四组数据都是大于等于7的，所以答案为4

示例2
输入

10 10000000

1 2 3 4 5 6 7 8 9 10

输出

0

解题思路
因为都是正整数，所以只要前面的数字和满足条件了，则后面所有的数字组合都满足。

代码
let n = Number(readLine());
let x = Number(readLine());
let ints = readLine().split(" ");
 
// let n = Number("3");
// let x = Number("7");
// let ints = "3 4 7".split(" ");
 
let count;  //连续正数和
let res = 0;
 
for(let i=0;i<n;i++){
    count = Number(ints[i]);    //当前数字
    /**
     * 因为是正整数，所以如果当前数字符合要求
     * 则由此往后的连续和都符合要求
     * 连续区间数为长度n-当前数字下标i
     */
    if(count>=x){
        res+=n-i;
        break;
    }
    for (let j=i+1;j<n;j++){
        count+=Number(ints[j]);
        if(count>=x){
            res+=n-j;
            break;
        }
    }
}
console.log(res);

--------------------------
标题： 斗地主 之顺子 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
在斗地主 扑克牌游戏 中， 扑克牌由小到大的顺序为：3,4,5,6,7,8,9,10,J,Q,K,A,2，玩家可以出的扑克牌阵型有：单张、对子、顺子、飞机、炸弹等。

其中顺子的出牌规则为：由至少5张由小到大连续递增的扑克牌组成，且不能包含2。

例如：{3,4,5,6,7}、{3,4,5,6,7,8,9,10,J,Q,K,A}都是有效的顺子；而{J,Q,K,A,2}、 {2,3,4,5,6}、{3,4,5,6}、{3,4,5,6,8}等都不是顺子。

给定一个包含13张牌的数组，如果有满足出牌规则的顺子，请输出顺子。

如果存在多个顺子，请每行输出一个顺子，且需要按顺子的第一张牌的大小（必须从小到大）依次输出。

如果没有满足出牌规则的顺子，请输出No。

输入描述:

13张任意顺序的扑克牌，每张扑克牌数字用空格隔开，每张扑克牌的数字都是合法的，并且不包括大小王：

2 9 J 2 3 4 K A 7 9 A 5 6

不需要考虑输入为异常字符的情况

输出描述:

组成的顺子，每张扑克牌数字用空格隔开：

3 4 5 6 7

示例1
输入

2 9 J 2 3 4 K A 7 9 A 5 6

输出

3 4 5 6 7

说明

13张牌中，可以组成的顺子只有1组：3 4 5 6 7

示例2
输入

2 9 J 10 3 4 K A 7 Q A 5 6

输出

3 4 5 6 7

9 10 J Q K A

说明

13张牌中，可以组成2组顺子，从小到大分别为：3 4 5 6 7 和 9 10 J Q K A

示例3
输入

2 9 9 9 3 4 K A 10 Q A 5 6

输出

No

说明

13张牌中，无法组成顺子

解题思路
1、将输入转换成集合，将2剔除（不参与排序），J、Q、K转换成数字11，12，13

2、对处理过的集合进行排序，方便找顺子

3、 从第一个数字开始遍历，判断相邻数字是否严格递增（相差1）：若数字相同则跳过；若严格递增，则添加到集合中；若不相同也不严格递增，则判断集合的长度是否大于等于5：若大于等于5则符合顺子，添加到顺子集合中。

4、若集合长度小于5则判断是否整个集合都遍历完全：若遍历完全，则直接退出整个循环；若没有遍历完全，则剃除步骤3处理过的数字；再重复步骤3。

5、将得到的数据还原，11、12、13还原成J、Q、K

代码
let s = readLine().split(" ");
//let s = "2 9 J 10 3 4 K A 7 Q A 5 6".split(" ");
let len = s.length;
let list = [];
 
for(let i=0;i<len;i++){ //剔除2，转化A,J,Q,K
    switch (s[i]){
        case "J":
            list.push(11);
            break;
        case "Q":
            list.push(12);
            break;
        case "K":
            list.push(13);
            break;
        case "A":
            list.push(14);
            break;
        case "2":
            break;
        default:
            list.push(Number(s[i]));
    }
}
 
list.sort((a,b)=>{
    return a-b;
}); //从小到大排序方便取值2 9 J 10 2 3 4 K A 7 Q A 5 6
 
let ress = [];
 
let isA = false; //是否遍历完整个数组
 
while (!isA){
    let res = [];
    res.push(list[0]);   //放入第一个数字
    let count = 1;
    for(let i=1;i<list.length;i++){
        let x = list[i];    //  本次数字
        if(x==list[i-1]+1){ //符合严格递增
            count++;
            res.push(x);
        }else if(x==list[i-1] && i!=list.length-1){
            continue;   //本次数字等于前面一个数字且不是数组最后一位,则进入下次循环
        }
        if(x!=list[i-1]+1 || i==list.length-1){
            if(count>=5){   //符合顺子
                ress.push(res);
            }else if(i==list.length-1){   //整个数组遍历完全，直接退出
                isA = true;
                break;
            }
            for(let j=0;j<res.length;j++){
                for(let k=0;k<list.length;k++){
                    if(res[j] == list[k]){
                        list.splice(list.indexOf(list[k]),1); //剔除已经处理过的数字
                        break;
                    }
                }
            }
            if(list.length<5){  //集合剩余数字不满足成为顺子
                isA = true;
            }
            break;  //顺子已经提取，跳出本次循环
        }
    }
}
 
if(ress.length==0){
    console.log("No");
}else {
    for(let i=0;i<ress.length;i++){
        let stringRes = "";
        for(let j=0;j<ress[i].length;j++){
            switch (ress[i][j]){    //将A\J\Q\K还原
                case 11:
                    stringRes+="J";
                    break;
                case 12:
                    stringRes+="Q";
                    break;
                case 13:
                    stringRes+="K";
                    break;
                case 14:
                    stringRes+="A";
                    break;
                default:
                    stringRes+=ress[i][j];
            }
            if(j<ress[i].length-1){
                stringRes+=" ";
            }
        }
        console.log(stringRes);
    }
}

--------------------------
标题：日志排序 | 时间限制：1秒 | 内存限制：262144K | 语言不限
运维工程师 采集到某产品现网运行一天产生的日志N条，现需根据日志时间按时间先后顺序对日志进行排序。

日志 时间格式 为：

H:M:S.N

H表示小时(0-23)，M表示分钟(0-59)，S表示秒(0-59)，N表示毫秒(0-999)

时间可能并没有补齐，也就是说: 01:01:01.001，也可能表示为1:1:1.1

输入描述:

第一行输入一个整数N，表示日志条数，1<=N<=100000

接下来N行输入N个时间

输出描述:

按时间升序排序之后的时间

如果有两个时间表示的时间相同，则保持输入顺序

示例1
输入：

2

01:41:8.9

1:1:09.211

输出：

1:1:09.211

01:41:8.9

示例2
输入：

3

23:41:08.023

1:1:09.211

08:01:22.0

输出：

1:1:09.211

08:01:22.0

23:41:08.023

示例3
输入：

2

22:41:08.023

22:41:08.23

输出：

22:41:08.023

22:41:08.23

说明：

两个时间表示的时间相同，保持输入顺序

解题思路
        将日志时间按照时、分、秒、毫秒分割，然后再按照时、分、秒、毫秒进行 比较大小 ，如果时相同，则对分比较，如果分相同，则对秒进行比较，如果秒相同，则对毫秒进行比较，如果毫秒也相同，则顺序不变。

代码
var linNum = Number(readLine());
//var linNum = Number("2");
var lists = [];
 
//var test = ["01:41:8.9","1:1:09.211"];
 
for(let i=0;i<linNum;i++){
    var list = [];
    var strings = readLine().replace(".",":").split(":");
    //var strings = test[i].replace(".",":").split(":");
    for(let j=0;j<strings.length;j++){
        list.push(strings[j]);
    }
    lists.push(list);
}
 
lists.sort((a,b)=>{
    if(Number(b[0])>Number(a[0])){
        return -1;
    }
    if(Number(b[0])<Number(a[0])){
        return 1;
    }
    if(Number(b[1])>Number(a[1])){
        return -1;
    }
    if(Number(b[1])<Number(a[1])){
        return 1;
    }
    if(Number(b[2])>Number(a[2])){
        return -1;
    }
    if(Number(b[2])<Number(a[2])){
        return 1;
    }
    if(Number(b[3])>Number(a[3])){
        return -1;
    }
    if(Number(b[3])<Number(a[3])){
        return 1;
    }
    return 1;
});
 
for(let i=0;i<linNum;i++){
    console.log(lists[i][0]+":"+
                lists[i][1]+":"+
                lists[i][2]+"."+
                lists[i][3]);
}

--------------------------
标题：最大N个数与最小N个数的和 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一个 数组 ，编写一个函数来计算它的最大N个数与最小N个数的和。你需要对数组进行去重。
说明：
       *数组中数字范围[0, 1000]
       *最大N个数与最小N个数不能有重叠，如有重叠，输入非法返回-1
*输入非法返回-1

输入描述:

第一行输入M， M标识数组大小

第二行输入M个数，标识数组内容

第三行输入N，N表达需要计算的最大、最小N个数

输出描述:

输出最大N个数与最小N个数的和。

示例1
输入

5

95 88 83 64 100

2

输出

342

说明

最大2个数[100,95],最小2个数[83,64], 输出为342

示例2
输入

5

3 2 3 4 2

2

输出

-1

说明

最大2个数[4,3],最小2个数[3,2], 有重叠输出为-1

解题思路
1、对输入的数组进行去重和排序。

2、使用shift()取得最小值，使用pop()取得最大值

代码
let m = Number(readLine());
let nums = readLine().split(" ").map(i=>parseInt(i));
let n = Number(readLine());
// let m = Number("5");
// let nums = "95 88 83 64 100".split(" ").map(i=>parseInt(i));
// let n = Number("2");
 
let treeSet = [];
 
for(let i=0;i<m;i++){
    if(treeSet.includes(nums[i])){
        continue;
    }
    treeSet.push(nums[i]);
}
 
treeSet.sort((a,b)=>{return a-b});
let count = 0;
 
if(treeSet.length<n*2){ //treeset长度小于n*2则表示最大最小数组有重复值
    count = -1;
}else {
    for(let i=0;i<n;i++){
        count += treeSet.shift() + treeSet.pop(); //最小和最大两个数之和
    }
}
 
console.log(count);

--------------------------
标题：最大矩阵和 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一个二维整数矩阵，要在这个矩阵中选出一个子矩阵，使得这个子矩阵内所有的数字和尽量大，我们把这个子矩阵称为和 最大子矩阵 ，子矩阵的选取原则是原矩阵中一块相互连续的矩形区域。

输入描述:

输入的第一行包含2个整数n, m(1 <= n, m <= 10)，表示一个n行m列的矩阵，下面有n行，每行有m个整数，同一行中，每2个数字之间有1个空格，最后一个数字后面没有空格，所有的数字的在[-1000, 1000]之间。

输出描述:

输出一行一个数字，表示选出的和最大子矩阵内所有的数字和。

示例1
输入

3 4

-3 5 -1 5

2 4 -2 4

-1 3 -1 3

输出

20

说明

一个3*4的矩阵中，后面3列的子矩阵求和加起来等于20，和最大。

解题思路
将第一行作为起始行，第一列作为起始列；将第一行作为终点行，从第一列向后遍历获取矩阵和。

如例（-3-->2-->1-->6）

在步骤1的基础上第二行作为终点行，从第一列向后遍历获取矩阵和。

如例（-1-->8-->5-->14）

在步骤2的基础上第三行作为终点行，从第一列向后遍历获取矩阵和。

以此类推。。。

将第一行作为起始行，第二列作为起始列；将第一行作为终点行，从第一列向后遍历获取矩阵和。

以此类推。。。

将第二行作为起始行，第一列作为起始列；将第一行作为终点行，从第一列向后遍历获取矩阵和。

以此类推。。。

最终找到最大值

注： 题中没有注明单行单列不符合要求，所以进行 全排列 ，如果当时候不能AC，可以调整一下，就是起始行和终点行不能为同一行，同样起始列与终点列不能为同一列。

代码
let n = Number(readLine());   //行
let m = Number(readLine());   //列
//let n = Number("3");   //行
//let m = Number("4");   //列
 
//let test = ["-3,5,-1,5","2,4,-2,4","-1,3,-1,3"];
 
let ints = [];
 
for(let i=0;i<n;i++){
    //let input = readLine().split(",").map(i=>parseInt(i));
    let input = test[i].split(",").map(i=>parseInt(i));
    let hang = [];
    for(let j=0;j<m;j++){
        hang[j] = input[j];
    }
    ints[i] = hang;
}
 
let max = 0;
for(let start_row = 0;start_row<n;start_row++){   //开始行
    for(let start_col = 0;start_col<m;start_col++){   //开始列
        for(let end_row = start_row;end_row<n;end_row++){   //结束行
            let jisuan = 0; //矩阵和
            for(let end_col = start_col;end_col<m;end_col++){   //结束列
                let rowindex = end_row; //将结束行作为边界
                while (rowindex>=start_row){    //最后一行不能超过开始行
                    jisuan+=ints[rowindex][end_col];    //从结束行向上遍历到开始行
                    rowindex--;
                }
                max = Math.max(max,jisuan);
            }
        }
    }
}
 
console.log(max);

--------------------------
标题：最小传输时延 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
某通信网络中有N个网络结点，用1到N进行标识。网络通过一个 有向无环图 表示，其中图的边的值表示结点之间的消息传递时延。
现给定相连节点之间的时延列表times[i]={u,v,w}，其中u表示源结点，v表示目的结点，w表示u和v之间的消息传递时延。请计算给定源结点到目的结点的最小传输时延，如果目的结点不可达，返回-1。
注：
1、N的取值范围为[1,100]；
2、时延列表times的长度不超过6000，且1 <= u,v <= N, 0 <= w <= 100；

输入描述:

输入的第一行为两个正整数，分别表示网络结点的个数N，以及时延列表的长度M，用空格分隔；
接下来的M行为两个结点间的时延列表[u v w]；
输入的最后一行为两个正整数u和v，分别表示源结点和目的结点；

输出描述:

输出一个整数，表示源结点到目的结点的最小时延。

示例1
输入

3 3

1 2 11

2 3 13

1 3 50

1 3

输出

24

说明

1->3的时延是50，1->2->3时延是11+13=24，所以1到3的最小时延是24；

解题思路
使用递归求得所有从初始节点到目标节点的时延，输出其中最小值。

代码
let input1 = readLine().split(" ").map(Number);
//let input1 = "4 6".split(" ").map(Number);
 
let N = input1[0];   //节点个数
let M = input1[1];   //时延列表长度
var res = [];    //完成传播的时延集合
var list = []; //时延列表的集合
//let test = ["1 2 11","2 3 13","1 3 50"];
//let test = ["1 2 4","1 3 1","1 4 100","2 3 2","2 4 6","3 4 1"];
 
for(let i=0;i<M;i++){
    let ints = readLine().split(" ").map(Number);
    //let ints = test[i].split(" ").map(Number);
 
    if((ints[0]<1 || ints[0]>N) ||
        (ints[1]<1 || ints[1]>N)){
        break;
    }
 
    list.push(ints);
}
 
let input2 = readLine().split(" ").map(Number);
//let input2 = "1 4".split(" ").map(Number);
 
let start = input2[0];   //初始节点
let end = input2[1]; //目标节点
 
qiushiyan(start, end, 0);
 
if(res.length == 0){
    console.log(-1);
}else {
    console.log(Math.min(...res));
}
 
/**
 *
 * @param start 初始节点
 * @param end   目标节点
 * @param count 时延总数
 */
function qiushiyan( start,  end,  count){
 
    for(let i=0;i<list.length;i++){
        let temp = list[i];
        if(temp[0]==start){
            if(temp[1]==end){
                res.push(count + temp[2]);
                continue;
            }
            qiushiyan(temp[1], end, count + temp[2]);
        }
    }
 
}

--------------------------
标题：最远足迹 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不
某探险队负责对地下洞穴进行探险。探险队成员在进行探险任务时，随身携带的记录器会不定期地记录自身的坐标，但在记录的间隙中也会记录其他数据。探索工作结束后，探险队需要获取到某成员在探险过程中相对于探险队总部的最远的足迹位置。

1. 仪器记录坐标时，坐标的数据格式为(x,y)，如(1,2)、(100,200)，其中0<x<1000，0<y<1000。同时存在非法坐标，如(01,1)、(1,01)，(0,100)属于非法坐标。

2. 设定探险队总部的坐标为(0,0)，某位置相对总部的距离为：x*x+y*y。

3. 若两个座标的相对总部的距离相同，则第一次到达的坐标为最远的足迹。

4. 若记录仪中的坐标都不合法，输出总部坐标（0,0）。

备注： 不需要考虑双层括号嵌套的情况，比如sfsdfsd((1,2))。

输入描述:

字符串，表示记录仪中的数据。

如：ferga13fdsf3(100,200)f2r3rfasf(300,400)

输出描述:

字符串，表示最远足迹到达的坐标。
如： (300,400)

示例1
输入

ferg(3,10)a13fdsf3(3,4)f2r3rfasf(5,10)

输出

(5,10)

说明

记录仪中的合法坐标有3个： (3,10)， (3,4)， (5,10)，其中(5,10)是相距总部最远的坐标， 输出(5,10)。

示例2
输入

asfefaweawfaw(0,1)fe

输出

(0,0)

说明

记录仪中的坐标都不合法，输出总部坐标（0,0）

解题思路
1、 遍历字符串 找出“(”、“)”的下标，然后将其坐标提取出来。

2、将符合要求的坐标放入列表中，找出其中最远距离，输出坐标。

代码
//let s = readline();
let s = "ferg(3,10)a13fdsf3(3,4)f2r3rfasf(5,10)";
 
let r = 0;
let l = 0;
let list = [];
let lists = [];
 
for(let i=0; i<s.length; i++){
    if(s.charAt(i)=='('){
        l = i+1;
    }else if(s.charAt(i)==')'){
        r = i;
    }
    if(r!=0){
        let ss = s.substring(l, r).split(",");  //利用小括号下标提取出坐标
        let j = Number(ss[0]);
        let w = Number(ss[1]);
        if(j>0 && j<1000 && w>0 && w<1000 && ss[0].charAt(0)!='0' && ss[1].charAt(0)!='0'){
            list.push(j);
            list.push(w);
            lists.push(list);
            list = [];
        }
        l = r =0;
    }
}
 
if(lists.length == 0){
    console.log("(0,0)");
}else {
    lists.sort((a,b)=>{ //对坐标进行降序排序
        let ax = a[0]*a[0]+a[1]*a[1];
        let bx = b[0]*b[0]+b[1]*b[1];
        if(bx>=ax){
            return 1;
        }
        return -1;
    });
 
    console.log("("+lists[0][0]+","+lists[0][1]+")");
}

--------------------------
标题：最长广播响应 | 时间限制：1秒 | 内存 限制：262144K | 语言限制：不限
某通信网络中有N个网络结点，用1到N进行标识。网络中的结点互联互通，且结点之间的消息传递有时延，相连结点的时延均为一个时间单位。

现给定网络结点的连接关系link[i]={u,v}，其中u和v表示网络结点。

当指定一个结点向其他结点进行广播，所有被广播结点收到消息后都会在原路径上回复一条响应消息，请计算发送结点至少需要等待几个时间单位才能收到所有被广播结点的响应消息。

注：

1、N的取值范围为[1,100]；

2、连接关系link的长度不超过3000，且1 <= u,v <= N；

3、网络中任意结点间均是可达的；

输入描述:

输入的第一行为两个正整数，分别表示网络结点的个数N，以及时延列表的长度I；

接下来的I行输入，表示结点间的连接关系列表；

最后一行的输入为一个正整数，表示指定的广播结点序号；

输出描述:

输出一个整数，表示发送结点接收到所有响应消息至少需要等待的时长。

示例1
输入

5 7

2 1

1 4

2 4

2 3

3 4

3 5

4 5

2

输出

4

说明

2到5的最小时延是2个时间单位，而2到其他结点的最小时延是1个时间单位，所以2收到所有结点的最大响应时间为2*2=4。

解题思路
1、通过递归，遍历出广播节点到其他所有节点的最小时延

2、找出步骤1中最大值，其值*2位最短时间单位

代码
//let input = readLine().split(" ").map(Number);
let input = "5 7".split(" ").map(Number);
let m = input[0];
let n = input[1];
 
let list = []; //信号集合
for(let i=1; i<=m; i++){
    list.push(i);
}
 
var linkArr = Array(m).fill().map(()=>Array(m).fill(0));   //信号联通数组
let test = ["2 1","1 4","2 4","2 3","3 4","3 5","4 5"];
//let test = ["2 3","3 1"];
for(let i=0; i<n; i++){
    //let int = readLine().split(" ").map(Number);
    let int = test[i].split(" ").map(Number);
    linkArr[int[0]-1][int[1]-1] = 1;
    linkArr[int[1]-1][int[0]-1] = 1;
}
 
//let start = Number(readLine());
let start = Number("2");
list.splice(start-1, 1);   //将广播节点移除
let max = 0;    //所有节点传播的最小时延
 
for(let i=0; i<m-1; i++){
    var min = Number.MAX_VALUE;    //广播的节点到各个节点之间的最小传播时延
    if(linkArr[start-1][list[i]-1] == 1 ||
        linkArr[list[i]-1][start-1] == 1){
        min = 1;
    }else{
        time(start-1, list[i]-1, []);
    }
    max = Math.max(max, min);
}
 
console.log(max*2);
 
function time( start, end, count){
 
    for(let i=0; i<linkArr.length; i++){
        if(!count.includes(i) && (linkArr[start][i] == 1 || linkArr[i][start] == 1)){
            if(i == end){
                min = Math.min(min, count.length+1);
            }else {
                let temp = []
                for(let j=0;j<count.length;j++){
                    temp.push(count[j]);
                }
                temp.push(i);
                time(i, end, temp);
            }
        }
    }
}

--------------------------
标题：最长方连续方波信号 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
输入一串方波信号，求取最长的完全连续交替方波信号，并将其输出，如果有相同长度的交替方波信号，输出任一即可，方波信号高位用1标识，低位用0标识，如图：



说明：

1） 一个完整的信号一定以0开始然后以0结尾，即010是一个完整信号，但101，1010，0101不是

2）输入的一串方波信号是由一个或多个完整信号组成

3） 两个相邻信号之间可能有0个或多个低位，如0110010，011000010

4） 同一个信号中可以有连续的高位，如01110101011110001010，前14位是一个具有连续高位的信号

5） 完全连续交替方波是指10交替，如01010是完全连续交替方波，0110不是

输入描述:

输入信号字符串（长度>=3且<=1024）：

0010101010110000101000010

注：输入总是合法的，不用考虑异常情况

输出描述:

输出最长的完全连续交替方波信号串：

01010

若不存在完全连续交替方波信号串，输出 -1

示例1
输入

00101010101100001010010

输出

01010

备注:

输入信号串中有三个信号：0 010101010110(第一个信号段) 00 01010(第二个信号段) 010(第三个信号段)

第一个信号虽然有交替的方波信号段，但出现了11部分的连续高位，不算完全连续交替方波，在剩下的连续方波信号串中01010最长

解题思路
根据题意可知：

信号方波要以0开始，以0结尾。

遍历字符串 ，遇到第一个0，开始统计

0 0101010101100001010010

遍历到第二个字符，还是0，则抛弃第一个0，从第二个0开始统计

0 0 101010101100001010010

遍历到第三个字符，是1，则符合方波

0 01 01010101100001010010

遍历到第四个字符，是0，注意：此时需要看第五个字符，如果第五个为1，则符合方波，如果为0，则方波统计结束

0 0101 010101100001010010

以此类推。。。

0 01010101011 00001010010

遍历到第十三个字符是0，符合方波

0 010101010110 0001010010

遍历到第十四个字符是0，因为前面一个字符已经是0，所以方波统计结束

0 010101010110 0 001010010

出现第一个方波 010101010110

继续遍历找出了另外两个方波

01010    010

因为需要连续方波，而连续的方波中间是10相互交替的，只有 01010和010符合，

最长的就是01010

代码
let s = readLine();
//let s = "00101010101100001010010";
 
let res = "";
let temp = "";
let b = false;  //是否开始识别
let isFomat = true; //是否满足条件
if(s.charAt(0)=='0'){       //如果第一个为0，则从第一个开始识别
    temp ="0";
    b = true;
}
 
for(let i=1;i<s.length;i++){
    if(b){      //识别中
        if(s.charAt(i)==s.charAt(i-1)){     //此时的数等于前一个数
            if(s.charAt(i)=='0'){       //出现重复的0则出局
                if(temp.length>=3 && isFomat){        //如果都是0，且符合规则（不含连续1大于3个长度）
                    res = temp.length>res.length ? temp : res;      //取最长信号
                }
                temp = "0";     //容器重置
                isFomat = true;
            }else {
                temp += s.charAt(i);      //出现重复的1继续，不过已不符合要求（不含连续的1）
                isFomat = false;
            }
        }else {
            temp += s.charAt(i);      //无重复的值则继续
        }
    } else {
        if(s.charAt(i)=='0'){   //遇到0就开始识别
            temp = "0";
            b = true;
        }
    }
}
console.log(res);

--------------------------
标题：最长的指定瑕疵度的元音子串 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
开头和结尾都是元音字母（aeiouAEIOU）的字符串为 元音字符串 ，其中混杂的非元音字母数量为其 瑕疵度 。比如:

·         “a” 、 “aa”是元音字符串，其瑕疵度都为0

·         “aiur”不是元音字符串（结尾不是元音字符）

·         “abira”是元音字符串，其瑕疵度为2

给定一个字符串，请找出指定瑕疵度的最长元音字符子串，并输出其长度，如果找不到满足条件的元音字符子串，输出0。

子串：字符串中任意个连续的字符组成的 子序列 称为该字符串的子串。

输入描述:

首行输入是一个整数，表示预期的瑕疵度flaw，取值范围[0, 65535]。
接下来一行是一个仅由字符a-z和A-Z组成的字符串，字符串长度(0, 65535]。

输出描述:

输出为一个整数，代表满足条件的元音字符子串的长度。

示例1
输入

0

asdbuiodevauufgh

输出

3

说明

 满足条件的最长元音字符子串有两个，分别为uio和auu，长度为3。

示例2
输入

2

aeueo

输出

0

说明

没有满足条件的元音字符子串，输出0

示例3
输入

1

aabeebuu

输出

5

说明

满足条件的最长元音字符子串有两个，分别为aabee和eebuu，长度为5

解题思路
对字符串进行连续辅音和连续元音字符的计算，如下：

蓝色为元音，红色为辅音

3

kasdbuiodevauufgh

1 1 3 3 1 1 1 3 3

注：因为前后都要是元音，所有剔除头尾的辅音段——> 1 3 3 1 1 1 3

先取出 1 3 3 ，其中辅音个数为 3 ==3，符合要求，长度为6

接着取出 1 3 ，加上11——> 3 1 1 ，辅音个数为1<3，需要继续叠加——> 3 1 1 1 3 ，辅音个数为 1 + 1 =2<3，继续叠加，但是已经到了末尾，所有最长为7

代码
let n = Number(readLine());
let str = readLine();
// let n = Number("3");
// let str = "kasdbuiodevauufgh";
 
let yuanyin = "aeiouAEIOU";
let len = str.length;
let list = []; //连续元音和辅音个数集合
let countYY = 0;    //连续元音个数
let countFY = 0;    //连续辅音个数
 
for(let i=0; i<len; i++){
    let temp = String(str.charAt(i));
    if(yuanyin.includes(temp)){
        if(countFY != 0){   //辅音计算值有值，需要添加
            list.push(countFY);
            countFY = 0;
        }
        countYY++;
    }else {
        if(countYY != 0){
            list.push(countYY);
            countYY = 0;
        }
        countFY++;
    }
    if(i == len-1 && countYY != 0){ //因为开头结尾都必须是元音，所有剔除末尾的辅音
        list.push(countYY);
    }
}
 
if(!yuanyin.includes(String(str.charAt(0)))){   //因为开头结尾都必须是元音，所有剔除开头的辅音
    list.splice(0,1);
}
 
let size = list.length;
let indexLeft = 0;  //最左侧的元音索引
let max = 0;
let count = list[0];    //元音的个数
let xiaci = 0;  //瑕疵的个数
 
if(n == 0){ //当瑕疵为0，需要单拎出来
    for(let i=0; i<size; i+=2){
        max = Math.max(max, list[i]);
    }
}else {
    for(let i=1; i<size-1; i+=2){
        xiaci += list[i];
        count += list[i+1]; //加上瑕疵右边的元音个数
        if(xiaci >= n){
            if(xiaci == n){ //瑕疵度符合了，需要计算最大值
                max = Math.max(count + n, max);
            }
            count -= list[indexLeft];   //元音减去最左侧的元音个数
            xiaci -= list[indexLeft+1];   //瑕疵减去最左侧的瑕疵个数
            indexLeft += 2;    //最左侧索引需要右移两个单位
        }
    }
}
 
console.log(max);

--------------------------
标题：最长的顺子 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
斗地主 起源于湖北十堰房县，据传是一位叫吴修全的年轻人根据当地流行的扑克玩法“跑得快”改编的，如今已风靡整个中国，并流行于互联网上。

牌型:

单顺, 又称顺子，最少5张牌，最多12张牌（3⋯A），不能有2，也不能有大小王，不计花色

例如：3-4-5-6-7-8，7-8-9-10-J-Q，3-4-5-6-7-8-9-10-J-Q-K-A

可用的牌 3<4<5<6<7<8<9<10<J<Q<K<A<2 < B(小王)< C(大王)，每种牌除大小王外有4种花色(共有 13X4 + 2 张牌)

输入1. 手上已有的牌 2. 已经出过的牌（包括对手出的和自己出的牌）

输出: 对手可能构成的最长的顺子(如果有相同长度的顺子, 输出牌面最大的那一个)，如果无法构成顺子, 则输出 NO-CHAIN

输入描述:

输入的第一行为当前手中的牌

输入的第二行为已经出过的牌

输出描述:

最长的顺子

示例1
输入

3-3-3-3-4-4-5-5-6-7-8-9-10-J-Q-K-A

4-5-6-7-8-8-8

输出

9-10-J-Q-K-A

示例2
输入

3-3-3-3-8-8-8-8

K-K-K-K

输出

NO-CHAIN

说明

剩余的牌无法构成顺子

解题思路
1、根据手上的牌和出过的牌，找出已经出完的牌（已出现四次的牌）

2、初始化一个完整牌序的集合3-A（2不进行顺子），再剔除步骤1已出完的牌，得到对手手上存在的牌

3、根据顺子的规则找出步骤2中最长的顺子

代码
let str1 = readLine().split("-");
let str2 = readLine().split("-");
// let str1 = "3-3-3-3-4-4-5-5-6-7-8-9-10-J-Q-K-A".split("-");
// let str2 = "4-5-6-7-8-8-8".split("-");
 
let len1 = str1.length;
let len2 = str2.length;
 
let map = new Map();  //当前手中的牌和出过的牌的键值对
 
for(let i=0;i<len1;i++){
    if(map.get(str1[i])){
        map.set(str1[i],map.get(str1[i])+1);
    }else{
        map.set(str1[i],1);
    }
}
 
for(let i=0;i<len2;i++){
    if(map.get(str2[i])){
        map.set(str2[i],map.get(str2[i])+1);
    }else{
        map.set(str2[i],1);
    }
}
 
let list = []; //对手的牌（除去2）
let listFour = []; //已经出了4张的牌
for(let i=3;i<=14;i++){
    list.push(i);
}
 
map.forEach((v,k)=>{
    if(v==4){
        let n;
        switch (k){
            case "J":
                n = 11;
                break;
            case "Q":
                n = 12;
                break;
            case "K":
                n = 13;
                break;
            case "A":
                n = 14;
                break;
            default:
                n = Number(k);
        }
        listFour.push(n);
    }
});
 
for(let i=0;i<listFour.length;i++){ //剔除已经出过四张的牌
    for(let j=0;j<list.length;j++){
        if(listFour[i] == list[j]){
            list.splice(j,1);
        }
    }
}
 
let res = [];  //最长顺子
let temp = []; //顺子容器，用来判断是否是顺子，是否是最长的顺子
let count = 1;  //连续牌的个数
let max = 0;    //最长顺子长度
temp.push(list[0]);
 
for (let i=1; i<list.length; i++){
    if(list[i]-list[i-1] == 1){
        temp.push(list[i]);
        count++;
        if(i==list.length-1 && count>=5 && count==Math.max(max,count)){ //最后一张牌也需要进行判断
            res = temp;
        }
    }else {
        if(count>=5 && count==Math.max(max,count)){
            res = temp;
        }
        temp = [];   //容器置空
        temp.push(list[i]);
        count=1;
    }
}
 
if(res.length == 0){
    System.out.println("NO-CHAIN");
}else {
    let s = "";
    for(let i=0;i<res.length;i++){
        let n = res[i];
        switch (n){
            case 11:
                s += "J";
                break;
            case 12:
                s += "Q";
                break;
            case 13:
                s += "K";
                break;
            case 14:
                s += "A";
                break;
            default:
                s += String(n);
        }
        if(i!=res.length-1){
            s+="-";
        }
    }
    console.log(s);
}

--------------------------
标题：服务器广播 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
服务器连接方式包括直接相连，间接连接。A和B直接连接，B和C直接连接，则A和C间接连接。直接连接和间接连接都可以发送广播。

给出一个N*N数组，代表N个服务器，matrix[i][j] == 1，则代表i和j直接连接；不等于1时，代表i和j不直接连接。matrix[i][i] == 1，即自己和自己直接连接。matrix[i][j] == matrix[j][i]。

计算初始需要给几台服务器广播，才可以使每个服务器都收到广播。

输入描述:

输入为N行，每行有N个数字，为0或1，由空格分隔，构成N*N的数组，N的范围为 1<=N<=40

输出描述:

输出一个数字，为需要广播的服务器的数量

示例1
输入

1 0 0

0 1 0

0 0 1

输出

3

说明

3台服务器互不连接，所以需要分别广播这3台服务器

示例2
输入

1 1

1 1

输出

1

说明

2台服务器相互连接，所以只需要广播其中一台服务器

解题思路
将输入的二阶数组转化为服务器联通对集合。

如例2：

【【1,1】【1,2】【2,2】】

1、取出第一个元素【1,1】去重得【1】，对剩下的【【1,2】【2，2】】进行遍历，第一个元素【1,2】包含了1，则剔除，得【【2,2】】，服务器集合为【1,2】；

2、重复步骤1，直至集合的元素全部取出。计算步骤进行次数。

代码
let input = readline().split(" ").map(Number);
//let input = "1 1 0 0".split(" ").map(Number);
 
let n = input.length;   //确定是n阶数组
var list = []; //服务器连通对集合
 
for(let i=0; i<n; i++){
    if(input[i] == 1){   //说明两个服务器相连
        let temp = [];
        temp.push(1);
        temp.push(i+1);
        list.push(temp);
    }
}
 
//let test = ["1 1 0 0","1 1 0 1","0 0 1 1","0 1 1 1"];
for(let i=1; i<n; i++){
    input = readline().split(" ").map(Number);
    //input = test[i].split(" ").map(Number);
    for(let j=0; j<n; j++){
        if(input[j]==1 && j>=i){    //两个服务器相连，剔除冗余数据
            let temp = [];
            temp.push(i+1);
            temp.push(j+1);
            list.push(temp);
        }
    }
}
 
let res = 0;
while (list.length>0){
    let temp = list[0];
    list.splice(0,1);
    connectNet(temp);
    res++;
}
 
console.log(res);
 
/**
 *
 * @param intList   相连的服务器集合（集合中的所有服务器都可以进行通信）
 */
function connectNet(intList){
    for(let i=0; i<list.length; i++){
        let temp = list[i];
        let a = temp[0];
        let b = temp[1];
        if(intList.includes(a) || intList.includes(b)){
            temp.forEach(element => {
                if(!intList.includes(element)){
                    intList.push(element);
                }
            });
            list.splice(i,1);
            connectNet(intList);
        }
    }
}

--------------------------
标题：服务失效判断 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
某系统中有众多服务，每个服务用字符串（只包含字母和数字，长度<=10）唯一标识，服务间可能有依赖关系，如A依赖B，则当B故障时导致A也故障。

依赖具有传递性，如A依赖B，B依赖C，当C故障时导致B故障，也导致A故障。

给出所有依赖关系，以及当前已知故障服务，要求输出所有正常服务。

依赖关系：服务1-服务2  表示“服务1”依赖“服务2”

不必考虑输入异常，用例保证：依赖关系列表、故障列表非空，且依赖关系数，故障服务数都不会超过3000，服务标识格式正常。

输入描述:

半角逗号分隔的依赖关系列表（换行）

半角逗号分隔的故障服务列表

输出描述:

依赖关系列表中提及的所有服务中可以正常工作的服务列表，用半角逗号分隔，按依赖关系列表中出现的次序排序。

特别的，没有正常节点输出单独一个半角逗号。

示例1
输入

a1-a2,a5-a6,a2-a3

a5,a2

输出

a6,a3

说明

a1依赖a2，a2依赖a3，所以a2故障，导致a1不可用，但不影响a3；a5故障不影响a6。所以可用的是a3、a6，在依赖关系列表中a6先出现，所以输出:a6,a3

示例2
输入

a1-a2

a2

输出

,

说明

a1依赖a2，a2故障导致a1也故障，没有正常节点，输出一个逗号

解题思路
1、根据输入，整理出所有服务listSer，并将其中故障服务剔除。

解法一：

遍历list Ser中所有的服务，根据依赖关系，判断其服务的正依赖树服务中是否有故障，如果有故障，则服务也为故障；如果没有，则服务正常。

解法二：

遍历故障服务，通过依赖关系，将其服务的反依赖树中的所有服务查找出来，最后将其从listSer中剔除，剩余的则为正常服务。

如： a-b，b-c，c-d

b，c，d为a的正依赖树，判断a是否正常，需要判断b，c，d是否正常，其中有一个故障，则a服务故障

a，b，c为d的反依赖树，d故障，则a，b，c故障

代码
let strings = readLine().split(",");
let errorSer = readLine().split(",");
//let strings = "a1-a2,a5-a6,a2-a3".split(",");
//let errorSer = "a5,a2".split(",");
 
let errorLen = errorSer.length;
var list = [];    //依赖关系集合
let listSer = [];   //所有服务
 
for(let i=0; i<strings.length; i++){
 
    let temp = strings[i].split("-");
 
    list.push(temp);
    let a = temp[0];
    let b = temp[1];
 
    if(!listSer.includes(a)) listSer.push(a);
    if(!listSer.includes(b)) listSer.push(b);
}
 
for(let i=0; i<errorLen; i++){
    checkError(errorSer[i]);
}
 
let resList = listSer.filter(v=> !errorSer.includes(v));    //从所有服务中剔除故障服务
if(resList.length == 0){
    console.log(",");
}else {
    let res = "";
    for(let i=0; i<resList.length; i++){
        res += resList[i];
        if(i != resList.length-1){
            res += ",";
        }
    }
    console.log(res);
}
 
/**
 *
 * @param s 故障服务
 * 请求出所有依赖故障服务的服务，并将其放入故障服务集合中
 */
function checkError( s){
 
    for(let i=0; i<list.length; i++){
        let temp = list[i];
        if(temp[1] == s && !errorSer.includes(temp[0])){
            errorSer.push(temp[0]);
            checkError(temp[0]);
        }
    }
}

--------------------------
标题：机器人走 迷宫  | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
1、 房间由X*Y的方格组成，例如下图为6*4的大小。每一个方格以坐标(x，y)描述。
2、 机器人固定从方格(0，0)出发，只能向东或者向北前进。出口固定为房间的最东北角，如下图的方格(5，3)。用例保证机器人可以从入口走到出口。
3、 房间有些方格是墙壁，如(4，1)，机器人不能经过那儿。

4、 有些地方是一旦到达就无法走到出口的，如标记为B的方格，称之为陷阱方格。

5、 有些地方是机器人无法到达的的，如标记为A的方格，称之为不可达方格，不可达方格不包括墙壁所在的位置。

6、 如下示例图中，陷阱方格有2个，不可达方格有3个。

7、 请为该机器人实现 路径规划 功能：给定房间大小、墙壁位置，请计算出陷阱方格与不可达方格分别有多少个。



输入描述:

1） 第一行为房间的的X和Y (0<X,Y<=1000)
2） 第二行为房间中墙壁的个数N（0<=N<X*Y）
3） 接着下面会有N行墙壁的坐标
同一行中如果有多个数据以一个空格隔开，用例保证所有的输入数据均合法。（结尾不带回车换行）

输出描述:

1）陷阱方格与不可达方格数量，两个信息在一行中输出，以一个空格隔开。（结尾不带回车换行）

示例1
输入

6 4

5

0 2

1 2

2 2

4 1

5 1

输出

2 3

说明

该输入对应上图示例中的迷宫，陷阱方格有2个，不可达方格有3个

示例2
输入

6 4

4

2 0

2 1

3 0

3 1

输出

0 4

说明

该输入对应的迷宫如下图，没有陷阱方格，不可达方格有4个，分别是(4, 0) (4, 1) (5, 0) (5, 1)



 

解题思路
将地图转换成二维数组，以例一为准，地图转换如下：

机器人初始位置在【0,0】，出口在【5,3】，方向向下和向右

值为0表示没有走过，-1表示墙，1表示能通过，2表示死路



代码
/**
 *  -1  表示墙
 *  0   表示没有走过的，无法到达之地
 *  1   表示可以到达的
 *  2   表示死路
 */
// let input = readline().split(" ").map(Number);
// let n = Number(readline());
let input = "6 4".split(" ").map(Number);
let n = Number("5");
 
var x = input[0];
var y = input[1];
var room = Array(x).fill().map(()=>Array(y).fill(0));
 
let test = ["0 2","1 2","2 2","4 2","5 2"];
 
while (n-- > 0)
{
    //input = readline().split(" ").map(Number);
    input = test[4-n].split(" ").map(Number);
    room[input[0]][input[1]] = -1;  //-1表示有墻
}
 
out(0, 0);
 
let countA = 0, countB = 0;
for(let i = 0; i < x; i++){
    for(let j = 0; j < y; j++){
        if(room[i][j] == 2){    //2表示死路
            countB++;
        }else if(room[i][j] == 0){  //表示沒有走过的路，即无法到达的地方
            countA++;
        }
    }
}
 
console.log(countB + " " + countA);
 
function out( i, j)
{
    if(i==x-1 && j==y-1){   //表示到达终点，也就是出口
        room[i][j] = 1; //终点可以到达，设置为1
        return;
    }
    if(room[i][j] != 0){    //已经确定了不需要再次确定
        return;
    }
    if(i<x-1){  //没有到达x轴边界，继续探索
        out(i+1,j);
    }
    if(j<y-1){  //没有到达y轴边界，继续探索
        out(i,j+1);
    }
    if(i==x-1 || j==y-1){   //到达边界
        if(i==x-1 && j<y-1 && room[i][j+1]!=1){
            room[i][j] = 2; //到达x轴边界，上边是不可到达的，则此格为死路
        }else if(j==y-1 && i<x-1 && room[i+1][j]!=1){
            room[i][j] = 2; //到达y轴边界，右边是不可到达的，则此格为死路
        }else {
            room[i][j] = 1; //可以到达的格子
        }
    }else if(room[i][j+1]!=1 && room[i+1][j]!=1){
        room[i][j] = 2; //右边和上边都是不可到达，则此格为死路
    }else {
        room[i][j] = 1; //可到达的格子
    }
}

--------------------------
标题：构成的正方形数量 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
输入N个互不相同的二维整数坐标, 求这N个坐标可以构成的正方形数量。( 内积 为零的两个向量垂直)

输入描述:

第一行输入为 N，N 代表坐标数量，N为正整数。N <= 100

之后的 K 行输入为坐标 x y以空格分隔，x, y 为整数, -10<=x, y <= 10

输出描述:

输出可以构成的正方形数量

示例1
输入

3

1 3

2 4

3 1

输出

0

说明

3 个点不足以构成正方形

示例2
输入

4

0 0

1 2

3 1

2 -1

输出

1

说明

此4点可构成正方形

解题思路
求出四个坐标的所有向量值，总共有6个。如果其中四个相等，且另外两个也相等，则表示构成正方形。

正方形的四个边相等，且对角线相等。

代码
let n = Number(readLine());
//let n = Number("4");
 
let list = [];
//let test = ["0 0","1 2","3 1","2 -1",];
 
for(let i=0;i<n;i++){
    let ints = readLine().split(" ").map(i=>parseInt(i));
    //let ints = test[i].split(" ").map(i=>parseInt(i));
    list.push(ints);
}
 
let count = 0;
let len = list.length;
if(len>3){
    for(let i=0;i<len-3;i++){
        for(let j=i+1;j<len-2;j++){
            for(let k=j+1;k<len-1;k++){
                for(let l=k+1;l<len;l++){
                    if(isZFX(list[i],list[j],list[k],list[l])){
                        count++;
                    }
                }
            }
        }
    }
}
 
console.log(count);
 
function isZFX( a, b, c, d){
 
    let list = [];
    list.push(a);
    list.push(b);
    list.push(c);
    list.push(d);
    let map = [];
    let temp = 0;
    let count = 0;
    for(let i=0;i<3;i++){
        for(let j=i+1;j<4;j++){
            let x = list[i][0]-list[j][0];
            let y = list[i][1]-list[j][1];
            let len = x*x + y*y;    //求四个坐标六个向量的长度
            temp = len;
            if(map[temp]!=undefined){
                map[temp] = map[temp]+1;
            }else{
                map[temp] = 1;
                count++;
            }   
        }
    }
 
    if(count ==2 && (map[temp]==2 || map[temp]==4)){    //六条向量有四条相等且另外两条也相等则构成正方形
        return true;
    }
 
    return false;
}

--------------------------
标题：查找 众数 及中位数 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
1.众数是指一组数据中出现次数量多的那个数，众数可以是多个

2. 中位数 是指把一组数据从小到大排列，最中间的那个数，如果这组数据的个数是奇数，那最中间那个就是中位数，如果这组数据的个数为偶数，那就把中间的两个数之和除以2，所得的结果就是中位数

3.查找整型数组中元素的众数并组成一个新的数组，求新数组的中位数

输入描述:

输入一个一维整型数组，数组大小取值范围 0<N<1000，数组中每个元素取值范围 0<E<1000

输出描述:

输出众数组成的新数组的中位数

示例1
输入

10 11 21 19 21 17 21 16 21 18 15

输出

21

示例2
输入

2 1 5 4 3 3 9 2 7 4 6 2 15 4 2 4

输出

3

示例3
输入

5 1 5 3 5 2 5 5 7 6 7 3 7 11 7 55 7 9 98 9 17 9 15 9 9 1 39

输出

7

解题思路
1、将数据进行排序

2、遍历数据求出众数放入集合中

3、求出集合中的中位数

代码
let strings = readLine().split(" ").map(i=>parseInt(i));
//let strings = "10 11 21 19 21 17 21 16 21 18 15".split(" ").map(i=>parseInt(i));
//let strings = "2 1 5 4 3 3 9 2 7 4 6 2 15 4 2 4".split(" ").map(i=>parseInt(i));
 
let len = strings.length;
 
if(len == 1){
    console.log(strings[0]);
}else{
    let ints = [];
 
    for(let i=0;i<len;i++){
        ints[i] = strings[i];
    }
 
    ints.sort((a,b)=>{
        return a-b;
    });  //排序以便求出众数
 
    let list = []; //众数集合
    let max = 0;    //出现最多次数
    let count = 1;  //相同数字个数
    for(let i=1;i<ints.length;i++){
        if(ints[i]==ints[i-1]){
            count++;
        }else{
            /**
             * 若本轮数字出现次数count等于max
             *     则直接放入集合（众数可以是多个）
             * 若不等于
             *     若count==max，说明本轮数字是众数
             *          清空集合，并将本次数字加入集合
             */
            if(count==max){
                list.push(ints[i-1]);
            }else {
                max = Math.max(max,count);
                if(max == count){
                    list = [];
                    list.push(ints[i-1]);
                }
            }
            count=1;
        }
        if(i==ints.length-1){   //遍历到最后一个数字
            if(count==max){
                list.push(ints[i]);
            }else {
                max = Math.max(max,count);
                if(max == count){
                    list = [];
                    list.push(ints[i]);
                }
            }
        }
    }
 
    let l = list.length;
    if(l%2==0){
        console.log((list[l/2-1]+list[l/2])/2);
    }else {
        console.log(list[(l+1)/2-1]);
    }
}

--------------------------
标题：根据某条件聚类最少交换次数 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给出数字K,请输出所有结果小于K的整数组合到一起的最少交换次数。

组合一起是指满足条件的数字相邻，不要求相邻后在数组中的位置。

数据范围

-100 <= K <= 100

-100 <=  数组中数值<=  100

输入描述:

第一行 输入数组 ：1 3 1 4 0 

第二行输入K数值：2 

输出描述:

第一行输出最少较好次数：1

示例1
输入

1 3 1 4 0

2

输出

1

示例2
输入

0 0 0 1 0

2

输出

0

示例3
输入

2 3 2

1

输出

0

备注:

小于2的表达式是1 1 0, 共三种可能将所有符合要求数字组合一起，最少交换1次

解题思路
1、计算出数组中满足条件的数字个数

2、以步骤1求出的数字长度作为区间长度，遍历数组在这些区间内不满足条件的个数，此值为此区间内的交换次数，其中最小值则为最少交换次数

注意 边界值 。

如例一

输入

1 3 1 4 0

2

131中不满足条件的只有一个3，3 1 4 不满足条件的有两个3、4，140中不满足的只有一个4，其中最小值为1，则输出1。

代码
let ints = readLine().split(" ").map(Number);
let n = Number(readLine());
// let ints = "1 3 1 4 0".split(" ").map(Number);
// let n = Number("2");
 
let len = ints.length;
let num = 0;    //满足条件的数字个数
 
for(let i=0; i<len; i++){
    if (ints[i] < n) {
        num++;
    }
}
 
let res = Number.MAX_VALUE;
for(let i=0; i<len-num+1; i++){
    let count = 0;
    for(let j=0; j<num; j++){
        if(ints[i+j]>=n){
            count++;
        }
    }
    res = Math.min(res, count);
}
 
console.log(res);

--------------------------
标题：检查是否存在满足条件的数字组合 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一个正整数数组，检查数组中是否存在满足规则的数字组合

规则：

A = B + 2C

输入描述:

第一行 输出数组 的元素个数。

接下来一行输出所有数组元素，用空格隔开。

输出描述:

如果存在满足要求的数，在同一行里依次输出规则里A/B/C的取值，用空格隔开。

如果不存在，输出0。

示例1
输入

4

2 7 3 0

输出

7 3 2

说明

7 = 3 + 2 * 2

示例2
输入

3

1 1 1

输出

0

说明

找不到满足条件的组合

备注:
1. 数组长度在3-100之间。

2. 数组成员为0-65535，数组成员可以重复，但每个成员只能在结果算式中使用一次。如：数组成员为[0, 0, 1, 5]，0出现2次是允许的，但结果0 = 0 + 2 * 0是不允许的，因为算式中使用了3个0。

3. 用例保证每组数字里最多只有一组符合要求的解。

解题思路
1、因为只有3个参数，所以比较简单的就是进行三层循环

2、备注已经表明最多只有一组符合要求的解，所以没有考虑比较复杂的数字重复使用的情况

代码
let n = Number(readLine());
let ints = readLine().split(" ").map(i=>parseInt(i));
// let n = Number("4");
// let ints = "2 7 3 0".split(" ").map(i=>parseInt(i));
 
let list = [];
 
for(let i=0;i<n;i++){   //对输入的list遍历 为A
    for(let j=0;j<n;j++){   //对输入的list遍历 为B
        if(i==j){   //下标相同为同一值，跳过
            continue;
        }
        for(let k=0;k<n;k++){
            if(i==k || j==k){ //下标相同为同一值，跳过
                continue;
            }
            if(ints[i] == ints[j] + 2*ints[k] ){    //进行A=B+2C处理判断
                let res = ints[i]+" "+ints[j]+" "+ints[k];
                list.push(res);
            }
        }
    }
}
 
if(list.length==0){
    console.log(0);
}else {
    list.forEach(v=>{
        console.log(v);
    })
}

--------------------------
标题：欢乐的周末 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
小华和小为是很要好的朋友，他们约定周末一起吃饭。通过手机交流，他们在地图上选择了多个聚餐地点（由于自然地形等原因，部分聚餐地点不可达），求小华和小为都能到达的聚餐地点有多少个？

输入描述:

第一行输入m和n，m代表地图的长度，n代表地图的宽度。

第二行开始具体输入地图信息，地图信息包含：

0 为通畅的道路

1 为障碍物（且仅1为障碍物）

2 为小华或者小为，地图中必定有且仅有2个 （非障碍物）

3 为被选中的聚餐地点（非障碍物）

输出描述:

可以被两方都到达的聚餐地点数量，行末无空格。

示例1
输入：

4 4

2 1 0 3

0 1 2 1

0 3 0 0

0 0 0 0

输出：

2

说明：

第一行输入地图的长宽为3和4。

第二行开始为具体的地图，其中：3代表小华和小明选择的聚餐地点；2代表小华或者小明（确保有2个）；0代表可以通行的位置；1代表不可以通行的位置。此时两者能都能到达的聚餐位置有2处

示例2
输入：

4 4

2 1 2 3

0 1 0 0

0 1 0 0

0 1 0 0

输出：

0

说明：

第一行输入地图的长宽为4和4。

第二行开始为具体的地图，其中：3代表小华和小明选择的聚餐地点；2代表小华或者小明（确保有2个）；0代表可以通行的位置；1代表不可以通行的位置。由于图中小华和小为之间有个阻隔，此时，没有两人都能到达的聚餐地址，故而返回0

备注:

地图的长宽为m和n，其中：

4 <= m <= 100

4 <= n <= 100

聚餐的地点数量为 k，则 

1< k <= 100

代码
//let input = readline().split(" ").map(Number);
let input = "4 4".split(" ").map(Number);
let lenX = input[0];    //长度
let lenY = input[1];    //宽度
 
let migong = [];    //迷宫数组
let hw = [];    //小华和小为的坐标
let canGuan = [];   //餐厅的坐标
 
//let test = ["2 1 0 3","0 1 2 1","0 3 0 0","0 0 0 0"];
let test = ["2 1 2 3","0 1 0 0","0 1 0 0","0 1 0 0"]
 
for (let i=0; i<lenY; i++) {
    migong[i] = [];
    //input = readline().split(" ").map(Number);
    input = test[i].split(" ").map(Number);
    for (let j=0; j<lenX; j++) {
        migong[i][j] = input[j];
        if (migong[i][j] == 2) {
            let h = [ i, j];
            hw.push(h);
        } else if (migong[i][j] == 3) {
            let c = [ i, j];
            canGuan.push(c);
        }
    }
}
 
let xh = hw[0];       //小华的位置坐标
let xw = hw[1];       //小为的位置坐标
let res = 0;
for (let i=0; i<canGuan.length; i++) {
    let temp = copy(migong);        //复制原数组（否则会导致数组改变）
    var endX = canGuan[i][0];       //餐馆横坐标
    var endY = canGuan[i][1];       //餐馆纵坐标
    if ( forEnd(xh[0], xh[1], temp) == 1 ) {
        temp = copy(migong);
        if ( forEnd(xw[0], xw[1], temp) == 1 ) {
            res++;
        }
    }
}
 
console.log(res);
 
function copy( nums){
    let x = nums.length;
    let y = nums[0].length;
    let res = [];
 
    for ( let i=0; i<x; i++) {
        res[i] = []
        for ( let j=0; j<y; j++) {
            res[i][j] = nums[i][j];
        }
    }
    return res;
}
 
function forEnd( x, y, ints){
 
    let U = x - 1;     //向上
    let D = x + 1;     //向下
    let L = y - 1;     //向左
    let R = y + 1;      //向右
 
    if(x==endX && y==endY){     //到达餐馆返回1
        return 1;
    }
 
    if (U>=0) {     //边界处理
        if (ints[U][y] != 1) {      //只要非1都能通过
            ints[x][y] = 1;     //能通过则本格置为1，表示已经走过
            if (forEnd(U,y,ints)==1) {      //递归处理，若值为1表示可以到达直接return 1
                return 1;
            }
        }
    }
 
    if (D<ints.length) {
        if (ints[D][y] != 1) {
            ints[x][y] = 1;
            if (forEnd(D,y,ints)==1) {
                return 1;
            }
        }
    }
 
    if (L>=0) {
        if (ints[x][L] !=1 ) {
            ints[x][y] = 1;
            if (forEnd(x,L,ints)==1) {
                return 1;
            }
        }
    }
 
    if (R<ints[0].length) {
        if (ints[x][R] != 1) {
            ints[x][y] = 1;
            if (forEnd(x,R,ints)==1) {
                return 1;
            }
        }
    }
 
    return 0;
}

--------------------------
标题：求字符串中所有整数的最小和 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
输入 字符串 s，输出s中包含所有整数的最小和

说明

1. 字符串s，只包含 a-z A-Z +- ；

2. 合法的整数包括

    1） 正整数 一个或者多个0-9组成，如 0 2 3 002 102

    2）负整数 负号 - 开头，数字部分由一个或者多个0-9组成，如 -0 -012 -23 -00023

输入描述:

包含数字的字符串

输出描述:

所有整数的最小和

示例1
输入

bb1234aa

输出

10

示例2
输入

bb12-34aa

输出

-31

说明

1+2+（-34） = 31

解题思路
求最小和，则需要保证正数足够小，负数足够大。当碰到负号时，则将后续连续的数字组成一个多位数；如没有负号，则每个数字都是一个单独的数。

新建一个temp对象，用来放置负号以及后面的连续数字；新建list对象用来放置最后求和的数字。

遍历输入的字符串：

1、如遇到数字，则判断是否存在负号的情况，若存在负号，则将temp进行拼接；若不存在则直接放入list，等待计算

2、如遇到负号，则判断temp中是否有值且是否是单独一个“-”字符串，若有值且非单独“-”字符串，则将其加入list；若没有值或者是单独“-”字符串，则不进行操作。最后temp赋值为“-”字符串

3、如遇到字母，则判断temp中是否有值且是否是单独一个“-”字符串，若有值且非单独“-”字符串，则将其加入list；若没有值或者是单独“-”字符串，则不进行操作。最后temp赋值为空字符串

代码
let s = readLine();
//let s = "bb12-34aa";
 
let len = s.length;
let list = [];
let temp = "";
let isFuhao = false;
let isDigit = /[0-9]/;  //数字正则
 
for(let i=0;i<len;i++){
    let c = s.charAt(i);
    if(isDigit.test(c)){
        if(isFuhao){
            temp += c;    //有负号的情况下数字越大越好，直接拼接
        }else {
            list.push(Number(c));   //没有负号直接加入集合
        }
    }else if(c=='-'){
        if(temp!="" && temp!="-"){    //temp中有值且不是一个“-”单字符串的情况下
            list.push(Number(temp));
        }
        isFuhao = true; //说明下一个字符串有了负号
        temp = "-";
    }else {
        /**
         字母和“+”的情况下进入
        * */
        if(temp!="" && temp!="-"){
            list.push(Number(temp));
        }
        temp = "";  //无论之前是什么，都需要置空
        isFuhao = false;
    }
}
let res = 0;
for (let i of list
        ) {
    res+=i;
}
console.log(res);

--------------------------
标题：求最多可以派出多少支团队 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
用 数组 代表每个人的能力，一个比赛活动要求参赛团队的最低能力值为N，每个团队可以由1人或2人组成，且1个人只能参加1个团队，请计算出最多可以派出多少支符合要求的团队？

输入描述:

5

3 1 5 7 9

8

第一行数组代表总人数，范围[1,500000]

第二行数组代表每个人的能力，每个元素的取值范围[1, 500000]，数组的大小范围[1,500000]

第三行数值为团队要求的最低能力值，范围[1, 500000]

输出描述:

3

最多可以派出的团队数量

示例1
输入

5

3 1 5 7 9

8

输出

3

说明

3,5组成一队，1,7组成一队，9自己一个队，故输出3

解题思路
1、先找出个人能力大于最低能力要求的队员个数

2、从剩余能力最大的队员开始，找到与他能力相加最接近最低能力要求的队员（从能力最低的队员向后遍历）

注意：队伍只能一个或两个队员，如果存在剩余能力最大的队员与之组队都无法高于最低能力要求，则将其剔除；先对能力进行升序排序。

代码
let n = Number(readLine());
let list = readLine().split(" ").map(Number);
let m = Number(readLine());
// let n = Number("5");
// let list = "3 1 5 7 9".split(" ").map(Number);
// let m = Number("8");
 
list.sort();
let count = 0;  //团队个数
let index;
 
for(index = n-1; index>=0; index--){
    if(list[index] >= m){ //个人能力大于最低要求，则符合
        count++;
    }else {
        break;  //不符合直接跳出
    }
}
 
for(let i=0, j=index; i<j; ){
    if(list[i]+list[j] >= m){
        count++;
        i++;
        j--;
    }else {
        i++;
    }
}
 
console.log(count);

--------------------------
标题：求满足条件的最长子串的长度 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
 给定一个 字符串 ，只包含字母和数字，按要求找出字符串中的最长（连续）子串的长度，字符串本身是其最长的子串，子串要求：

1、 只包含1个字母(a~z, A~Z)，其余必须是数字；

2、 字母可以在子串中的任意位置；

如果找不到满足要求的子串，如全是字母或全是数字，则返回-1。

输入描述:

字符串(只包含字母和数字)

输出描述:

子串的长度

示例1
输入

abC124ACb

输出

4

说明

满足条件的最长子串是C124或者124A，长度都是4

示例2
输入

a5

输出

2

说明

字符串自身就是满足条件的子串，长度为2

示例3
输入

aBB9

输出

2

说明

满足条件的子串为B9，长度为2

示例4
输入

abcdef

输出

-1

说明

没有满足要求的子串，返回-1

解题思路
1、求出连续的数字和字母长度并加入集合list中

        11111a1111aaa111 -> {5,1,4,3,3}

2、如果集合长度为1，则直接返回-1

3、判断输入的第一个字符是否为字母

        若为字母，则从0开始遍历，step为2，res = list.get(index+1)+1

        abcd1234a2341qaqq -> {4,4,1,4,4}    max = 9

        若为数字，则从1开始遍历，step为2，res = list.get(index-1)+1

        11111a1111aaa111 -> {5,1,4,3,3}        max = 10   

        主要针对字母在第一个，字母在中间和字母在最后三种情况进行判断，其中字母

        在中间且值为1（list.get(index)==1），res = list.get(index-1)+list.get(index+1)+1

代码
let s = readLine();
//let s = "1111a124ACb";
//let s = "abcdef";
let n = s.length;
 
let numLen = 0;    //连续数字长度
let zimuLen = 0;   //连续字母长度
let list = []; //连续数字和字母长度的集合
let res = -1;
let isDigit = /[0-9]/;
 
for(let i=0;i<n;i++){
    if(isDigit.test(s.charAt(i))){
        numLen++;
        if(zimuLen!=0){
            list.push(zimuLen);
            zimuLen = 0;
        }
    }else{
        zimuLen++;
        if(numLen!=0){
            list.push(numLen);
            numLen=0;
        }
    }
    if(i==n-1){ //最后一个字符
        list.push(numLen!=0 ? numLen : zimuLen);
    }
}
 
let listLen = list.length;
if(listLen != 1){
    let index = 0;
    if(isDigit.test(s.charAt(0))){
        index = 1;
    }
    for(let i=index;i<listLen;i+=2){
        if(i==0){   //第一个就是字母
            res = Math.max(res, list[i+1]+1);
        }else if(i != listLen-1){   //字母不在最后一个
            if(list[i] == 1){ //假如字母只有一个，则对前后相加
                res = Math.max(res, list[i-1]+list[i+1]+1);
            }else {
                res = Math.max(res, Math.max(list[i-1]+1, list[i+1]+1));
            }
        }else {
            res = Math.max(res, list[i-1]+1);   //字母在最后
        }
    }
}
 
console.log(res);

--------------------------
标题：流水线 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
一个工厂有m条 流水线 ，来并行完成n个独立的作业，该工厂设置了一个调度系统，在安排作业时，总是优先执行处理时间最短的作业。

现给定流水线个数m，需要完成的作业数n, 每个作业的处理时间分别为t1,t2…tn。请你编程计算处理完所有作业的耗时为多少？
当n>m时，首先处理时间短的m个作业进入流水线，其他的等待，当某个作业完成时，依次从剩余作业中取处理时间最短的进入处理。 

输入描述:

第一行为2个整数（采用空格分隔），分别表示流水线个数m和作业数n；

第二行输入n个整数（采用空格分隔），表示每个作业的处理时长t1,t2…tn。

0< m,n<100，0<t1,t2…tn<100。

注：保证输入都是合法的。

输出描述:

输出处理完所有作业的总时长

示例1
输入

3 5 

8 4 3 2 10

输出

13

说明

1、先安排时间为2、3、4的3个作业。

2、第一条流水线先完成作业，然后调度剩余时间最短的作业8。

3、第二条流水线完成作业，然后调度剩余时间最短的作业10。

4、总工耗时就是第二条流水线完成作业的时间13（3+10）。

解题思路
1、因为作业需要从最小的进行处理，所以对作业数进行升序排序

2、对作业数进行遍历，将其放入此刻时间最短的流水线中。

3、获取流水线中的最长时间

代码
let input = readLine().split(" ").map(i=>parseInt(i));
let ints = readLine().split(" ").map(i=>parseInt(i));    //作业数组
// let input = "3 5".split(" ").map(i=>parseInt(i));
// let ints = "8 4 3 2 10".split(" ").map(i=>parseInt(i));    //作业数组
 
let m = input[0];   //流水线
let n = input[1];   //作业数
 
ints.sort((a,b)=>{return a-b});  //对作业进行排序（升序）
 
let res = 0;    //最短流水线容器
let count = Array(m).fill(0);   //流水线数组
let index = 0;  //流水线索引
 
for(let i=0;i<n;i++){
    res = Math.min(...count);    //求流水线中最短时间的线
    for(let j=0;j<m;j++){
        if(res == count[j]){    //求出流水线最短时间线的下标
            index = j;
            break;
        }
    }
    count[index]+=ints[i];
}
 
console.log(Math.max(...count));    //求出最长流水线

--------------------------
标题：消消乐游戏 | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
游戏规则：输入一个只包含英文字母的字符串，字符串中的两个字母如果相邻且相同，就可以消除。

在字符串上反复执行消除的动作，直到无法继续消除为止，此时游戏结束。

输出最终得到的字符串长度。

输入描述:

输入原始字符串 str ，只能包含大小写英文字母，字母的大小写敏感， str 长度不超过100。

输出描述:

输出游戏结束后，最终得到的字符串长度

示例1
输入

gg

输出

0

说明

gg 可以直接消除，得到空串，长度为0

示例2
输入

mMbccbc

输出

3

说明

在 mMbccbc 中，可以先消除 cc ；此时字符串变成 mMbbc ，可以再消除 bb ；此时字符串变成 mMc ，此时没有相邻且相同的字符，无法继续消除。最终得到的字符串为 mMc ，长度为3

备注:

输入中包含 非大小写英文字母 时，均为异常输入，直接返回 0

解题思路
1、将数据分割为字符放入 list集合 中，list可以删除对应数据，并及时更新，以便后续继续处理

2、根据每次消除完数据都要从头开始遍历，我们给定一个变量n表示list数据长度，遍历一次n就-1，当n=0代表遍历完成，也就代表字符串无法继续消除，此时list的长度就是最终值

代码
let s = sc.nextLine();
//let s = "mMbccbc";
//let s = "gg";
 
let list = [];
let isFuhe = true;  //是否符合题意，只有大小写字母
var reg= /^[A-Za-z]+$/; //字母正则
 
for (let i=0;i<s.length;i++){
    let temp = s.charAt(i);
    if(!reg.test(temp)){
        isFuhe = false;
        break;
    }
    list.push(temp);  //用list容器，因为list能及时更新数据
}
let n = s.length; //list数组中所剩处理数据
 
while (n>0 && isFuhe){    //当所有数据处理完就退出
    n = list.length-1;  //因为从第二个数据开始处理，所以做了-1处理
    for(let i=1;i<list.length;i++){
        n--;    //处理一次，所剩数据-1
        if(list[i]==list[i-1]){ //有相同的字符进行清除
            list.splice(i,1);
            list.splice(i-1,1);
            break;  //list数据进行处理，处理完直接退出本次循环，重新开始新的循环
        }
    }
}
 
console.log(isFuhe ? list.length : 0);

--------------------------
标题：火星文计算 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
已知火星人使用的运算符为#、$，其与地球人的等价公式如下： 
x#y = 2*x+3*y+4 
x$y = 3*x+y+2 
1、其中x、y是无符号整数 
2、地球人公式按C语言规则计算 
3、火星人公式中，$的优先级高于#，相同的运算符，按从左到右的顺序计算 
现有一段火星人的字符串报文，请你来翻译并计算结果。 

输入描述:

火星人字符串表达式（结尾不带回车换行）

输入的字符串说明：  字符串为仅由无符号整数和操作符（#、$）组成的计算表达式。

例如 ：123#4$5#67$78。  

1、用例保证字符串中，操作数与操作符之间没有任何分隔符。  
2、用例保证操作数取值范围为32位无符号整数。  
3、保证输入以及计算结果不会出现整型溢出。  
4、保证输入的字符串为合法的求值报文，例如：123#4$5#67$78  
5、保证不会出现非法的求值报文，例如类似这样字符串：  
#4$5 //缺少操作数  
4$5# //缺少操作数  
4#$5 //缺少操作数  
4 $5 //有空格  
3+4-5*6/7 //有其它操作符  
12345678987654321$54321 //32位整数计算溢出

输出描述:

根据输入的火星人 字符串输出 计算结果（结尾不带回车换行）

示例1
输入

7#6$5#12

输出

226

说明 
7#6$5#12  
=7#(3*6+5+2)#12  
=7#25#12  
=(2*7+3*25+4)#12  
=93#12  
=2*93+3*12+4  
=226  

代码
//let s = readline();
let s = "7#6$5#12";
 
let num = [];
let fuhao = [];
let str = "";    //用来保存数字字符串
let numReg = new RegExp("^[0-9]{1}$");
 
for(let i=0; i<s.length; i++){
    if(numReg.test(s.charAt(i))){
        str += s.charAt(i);   //考虑到多位数需要拼接
        if(i == s.length-1){    //最后一个字符
            let n = Number(str);   //最后一个肯定是数字
            let f = fuhao.shift();
            if(f == '#'){
                num.push(n);    //如果是#则表示不计算
            }else {
                let m = num.pop();
                fuhao.pop();
                num.push(daole(m,n));   //如果是$进行计算
            }
        }
    } else {
        if(fuhao.length == 0){
            num.push(Number(str)); //上个str数字化push数字堆栈
            str = "";   //重置str
            fuhao.push(s.charAt(i));    //本次字符串push符合堆栈
        } else {
            let n = Number(str);   //str数字化
            let f = fuhao.shift();  //获取符号堆栈最上面的符号
            str = "";   //重置str
            if(f=='#'){
                num.push(n);    //#先不计算
            }else {
                let m = num.pop();  //获取数字堆栈最上面的数字
                fuhao.pop();    //移除符号堆栈最上面的符号
                num.push(daole(m,n));   //计算完push数字堆栈
            }
            fuhao.push(s.charAt(i));    //将本次的符号push符号堆栈
        }
    }
}
let n = num.length;
while (n>1){
    num.unshift(jinghao(num.shift(), num.shift()));    //剩下的数字直接进行#运算
    n--;
}
 
console.log(num.shift());
 
function jinghao( x, y){
    return 2*x+3*y+4;
}
 
function daole( x, y){
    return 3*x+y+2;
}

--------------------------
标题：火锅 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
入职后，导师会请你吃饭，你选择了火锅。
火锅里会在不同时间下很多菜。
不同食材要煮不同的时间，才能变得刚好合适。你希望吃到最多的刚好合适的菜，但是你的手速不够快，用m代表手速，每次下手捞菜后至少要过m秒才能再捞（每次只能捞一个）。
那么用最合理的策略，最多能吃到多少刚好合适的菜？

输入描述:

第一行两个整数n，m，其中n 代表往锅里下的菜的个数，m 代表手速。
接下来有n行，每行有两个数x，y 代表第x秒下的菜过y秒才能变得刚好合适。
(1 < n,m < 1000)
(1 <x, y<1000) 

输出描述:

输出一个整数代表用最合理的策略，最多能吃到刚好合适的菜的数量

示例1
输入

2 1

1 2

2 1

输出

1

说明

一共下了两个菜，在第一秒下的菜需要到第三秒吃，在第二秒下的菜也要到第三秒吃，所以只能吃一个

示例2
输入

3 1

1 2

1 3

2 3

输出

3

说明

一共下了两个菜，可以每秒捞一个，第一个在第一秒下的菜需要到第3秒吃，第二个在第一秒下的菜需要到第4秒吃，在第二秒下的菜也要到第5秒吃，所以三个都能吃到

解题思路
1、菜可以吃的秒数=下菜的秒数x+菜适合吃的秒数y

2、第一个菜可以直接吃，后面的菜必须在吃前一个菜的秒数上加上手速

3、同一秒的菜肯定只能吃一个

代码
let n = Number(readLine());
let m = Number(readLine());
// let n = Number("4");
// let m = Number("1");
 
let footList = [];
//let test = ["1 2","1 3","2 3","2 2"];
 
for(let i=0;i<n;i++){
    let nums = readLine().split(" ").map(i=>parseInt(i));
    //let nums = test[i].split(" ").map(i=>parseInt(i));
    footList.push(nums[0]+nums[1]); //所有菜的最佳时机
}
 
let list = [];  //对食物数组进行去重和排序
footList.forEach(v=>{
    if(!list.includes(v)){
        list.push(v);
    }
})
 
list.sort();
 
let count = 0;  //吃菜的次数
let len = list.length;
let time = 0;   //吃菜的时间
for(let i=0;i<len;i++){
    if(time <= list[i]){    //吃菜的时间小于菜的最佳时机，表示可以吃上
        count++;
        time = list[i]+m;   //这个菜吃完需要过m秒才能再次吃菜
    }
}
 
console.log(count);

--------------------------
标题：热点网站统计 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
企业路由器的统计页面，有一个功能需要动态统计公司访问最多的网页URL top N。请设计一个算法，可以高效动态统计Top N的页面。

输入描述:

每一行都是一个URL或一个数字，如果是URL，代表一段时间内的网页访问；如果是一个数字N，代表本次需要输出的Top N个URL。

输入约束：1、总访问网页数量小于5000个，单网页访问次数小于65535次；2、网页URL仅由字母，数字和点分隔符组成，且长度小于等于127字节；3、数字是正整数，小于等于10且小于当前总访问网页数；

输出描述:

每行输入要对应一行输出，输出按访问次数排序的前N个URL，用逗号分隔。

输出要求：1、每次输出要统计之前所有输入，不仅是本次输入；2、如果有访问次数相等的URL，按URL的字符串 字典序 升序排列，输出排序靠前的URL；

示例1
输入

news.qq.com

news.sina.com.cn

news.qq.com

news.qq.com

game.163.com

game.163.com

www.huawei.com

www.cctv.com

3

www.huawei.com

www.cctv.com

www.huawei.com

www.cctv.com

www.huawei.com

www.cctv.com

www.huawei.com

www.cctv.com

www.huawei.com

3

输出

news.qq.com,game.163.com,news.sina.com.cn

www.huawei.com,www.cctv.com,news.qq.com

示例2
输入

news.qq.com

www.cctv.com

1

www.huawei.com

www.huawei.com

2

3

输出

news.qq.com

www.huawei.com,news.qq.com

www.huawei.com,news.qq.com,www.cctv.com

解题思路
使用map键值对，key值对应网站名，value值记录访问次数

对map进行排序，找出value值排前N的网站

代码
let map = new Map();
let test = ["news.qq.com",
    "www.cctv.com",
    "1",
    "www.huawei.com",
    "www.huawei.com",
    "2",
    "3"
    ];
 
while (line = readline()){
//for(let i=0; i<test.length; i++){
 
    let str = line;
    //let str = test[i];
    if(!str.includes(".")){ //不包含.的就是数字
        let n = Number(str);
        if(n > map.size){   //如果数字大于网站个数这退出
            break;
        }
 
        let res = "";
        let mapArray = Array.from(map);
        mapArray.sort((a, b)=>{  //对list进行降序排序
            return b[1] - a[1];
        });
 
        for(let j=0; j<n; j++){
            res += mapArray[j][0] + ",";
        }
 
        console.log(res.substring(0, res.length-1));
    }else {
        if(map.has(str)){
            map.set(str, map.get(str)+1);
        }else{
            map.set(str, 1);
        }
    }
}

--------------------------
标题：猜密码 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
小杨申请了一个保密柜，但是他忘记了密码。只记得密码都是数字，而且所有数字都是不重复的。请你根据他记住的数字范围和密码的最小数字数量，帮他算下有哪些可能的组合，规则如下：

1、输出的组合都是从可选的数字范围中选取的，且不能重复；

2、输出的密码数字要按照从小到大的顺序排列，密码组合需要按照字母顺序，从小到大的顺序排序。

3、输出的每一个组合的数字的数量要大于等于密码最小数字数量；

4、如果可能的组合为空，则返回“None”

输入描述:

1、输入的第一行是可能的密码数字列表，数字间以半角逗号分隔

2、输入的第二行是密码最小数字数量

输出描述:

可能的密码组合，每种组合显示成一行，每个组合内部的数字以半角逗号分隔，从小到大的顺序排列。

输出的组合间需要按照 字典序排序 。

比如：

2,3,4放到2,4的前面

示例1
输入

2,3,4

2

输出

2,3

2,3,4

2,4

3,4

说明

最小密码数量是两个，可能有三种组合：

2,3

2,4

3,4

三个密码有一种：

2,3,4

示例2
输入

2,0

1

输出

0

0,2

2

说明

可能的密码组合，一个的有两种 ：

0

2

两个的有一个：

0,2

备注:

字典序是指按照单词出现在字典的顺序进行排序的方法，比如：

a排在b前

a排在ab前

ab排在ac前

ac排在aca前

解题思路
1、因为密码是升序的，所以首先要对输入的数字进行升序排序。

2、根据题意是从可选的密码数字列表中选出对应数量的数字作为密码。

也就是从M个字符中取出N个字符的 全排列 （经典算法）

3、因为最小数字数量是N，所以需要一直遍历到可选密码数字列表的长度，才能得到所有可能的密码

代码
let strings = readLine().split(",");
//let strings = "2,0".split(",");
 
strings.sort();   //先对输入数字进行升序，因为密码是升序的
let n = Number(readLine());
//let n = Number("1");
 
let len = strings.length;
var list = [];
 
for(let i=n;i<=len;i++){    //对数组从最小长度到最大长度求全组合排列
    combine(strings,i,new String(),0);
}
 
list.sort();
 
if(list.length==0){
    console.log("None");
}else {
    list.forEach(v=>{
        let str = "";
        for(let i=0;i<v.length;i++){
            str+=v.charAt(i);
            if(i!=v.length-1){
                str+=",";
            }
        }
        console.log(str);
    });
}
 
/**
 *  经典的 M 中取 N 个字符排列的递归算法，大家如果理解不了可以记一下
 * @param str    数字池（从中取数字）
 * @param n      数字个数（每添加一个数字进行减一，到0时满足，输出）
 * @param res    数字排列
 * @param index  下标（数字池中的索引）
 */
function combine(str, n, res, index){
 
    if(n==0){
        list.push(res);
    }else {
        for(let i=index;i<str.length;i++){
            res += str[i];
            combine(str,n-1,res,i+1);
            res = res.substring(0,res.length-1);  //非常关键的一步
        }
    }
}

--------------------------
标题：猴子爬山 | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
一天一只顽猴想去从山脚爬到山顶，途中经过一个有个N个台阶的阶梯，但是这猴子有一个习惯： 每一次只能跳1步或跳3步，试问猴子通过这个阶梯有多少种不同的跳跃方式？

输入描述:

输入只有一个整数N（0<N<=50）此阶梯有多少个阶梯

输出描述:

输出有多少种跳跃方式（解决方案数）

示例1
输入

50

输出

122106097

示例2
输入

3

输出

2

解题思路
1个台阶：(1)                                                                                                              1

2个台阶：(1,1)                                                                                                           1

3个台阶：(1,1,1)+(3)                                                                                                  2

4个台阶：(1,1,1,1)+(1,3)+(3,1)                                                                                   3

5个台阶：(1,1,1,1,1)+(1,1,3)+(1,3,1)+(3,1,1)                                                              4

6个台阶：(1,1,1,1,1,1)+(1,1,1,3)+(1,1,3,1)+(1,3,1,1)+(3,1,1,1)+(3,3)                         6

7个台阶：(1,1,1,1,1,1,1)+(1,1,1,1,3)+(1,1,1,3,1)+(1,1,3,1,1)+(1,3,1,1,1)+(3,1,1,1,1)

                (1,3,3)+(3,1,3)+(3,3,1)                                                                                 9

n个台阶：  f(n-1)+f(n-3)

这样一来代码就简单了

代码
let n = Number(readLine());
//let n = Number("50");
 
console.log(pashan(n));
    
function pashan( n){
    if(n==1){
        return 1;
    }
    if(n==2){
        return 1;
    }
    if(n==3){
        return 2;
    }
    return pashan(n-1) + pashan(n-3);
}

--------------------------
标题：玩牌高手 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
给定一个长度为n的 整型 数组，表示一个选手在n轮内可选择的牌面分数。选手基于规则选牌，请计算所有轮结束后其可以获得的最高总分数。选择规则如下：

1、在每轮里选手可以选择获取该轮牌面，则其总分数加上该轮牌面分数，为其新的总分数。

2、选手也可不选择本轮牌面直接跳到下一轮，此时将当前总分数还原为3轮前的总分数，若当前轮次小于等于3（即在第1、2、3轮选择跳过轮次），则总分数置为0。

3、选手的初始总分数为0，且必须依次参加每一轮。

输入描述:

第一行为一个小写逗号分割的字符串，表示n轮的牌面分数，1<= n <=20。

分数值为整数，-100 <= 分数值 <= 100。

不考虑格式问题。

输出描述:

所有轮结束后选手获得的最高总分数。

示例1
输入

1,-5,-6,4,3,6,-2

输出

11

说明

总共有7轮牌面。

第一轮选择该轮牌面，总分数为1。

第二轮不选择该轮牌面，总分数还原为0。

第三轮不选择该轮牌面，总分数还原为0。

第四轮选择该轮牌面，总分数为4。

第五轮选择该轮牌面，总分数为7。

第六轮选择该轮牌面，总分数为13。

第七轮如果不选择该轮牌面，则总分数还原到3轮以前分数，即第四轮的总分数4，如果选择该轮牌面，总分数为11，所以选择该轮牌面。

因此，最终的最高总分为11。

解题思路
需要将每次计算的值放在一个集合中，方便之后数据的比较

需要分两种情形：

1、前三个，如果选择该轮的总分大于0，则选择该轮牌面，否在总分还原为0

2、三之后的牌面，如果选择该轮的总分大于三轮前的分数，则选择该轮，否则放弃该轮牌面，并还原值三轮前的分数。

代码
let ints = readLine().split(",").map(i=>parseInt(i));
//let ints = "1,-5,-6,4,3,6,-2".split(",").map(i=>parseInt(i));
 
let len = ints.length;
let list = [];
 
if(ints[0]<=0){    //第一个不需要进行加法，单独处理
    list.push(0);
}else {
    list.push(ints[0]);
}
 
for(let i=1;i<len;i++){
    let count = list[i-1]+ints[i];
    if(i<3){    //前三个数
        list.push(count>0 ? count : 0);
    }else {
        list.push(count>list[i-3] ? count : list[i-3]);
    }
}
 
console.log(list[len-1]);

--------------------------
标题：用户调度问题 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
在通信系统中，一个常见的问题是对用户进行不同策略的调度，会得到不同的系统消耗和性能。

假设当前有n个待串行调度用户，每个用户可以使用A/B/C三种不同的调度策略，不同的策略会消耗不同的系统资源。请你根据如下规则进行用户调度，并返回总的消耗资源数。

规则：

1.     相邻的用户不能使用相同的调度策略，例如，第1个用户使用了A策略，则第2个用户只能使用B或者C策略。

2.     对单个用户而言，不同的调度策略对系统资源的消耗可以 归一化 后抽象为数值。例如，某用户分别使用A/B/C策略的系统消耗分别为15/8/17。

3.     每个用户依次选择当前所能选择的对系统资源消耗最少的策略（局部最优），如果有多个满足要求的策略，选最后一个。

输入描述:

第一行表示用户个数n

接下来每一行表示一个用户分别使用三个策略的系统消耗resA resB resC

输出描述:

最优策略组合下的总的系统资源消耗数

示例1
输入

3

15 8 17

12 20 9

11 7 5

输出

24

说明

1号用户使用B策略，2号用户使用C策略，3号用户使用B策略。系统资源消耗: 8 + 9 + 7 = 24。

备注:

所有策略对系统的资源消耗均为正整数，n < 1000

解题思路
1、根据题意就是求最优组合，我们可以使用递归来求出全组合结果

2、最后在结果中求出最小值

代码
var hu = Number(readLine());
//let hu = Number("3");
 
let temp = [];
// let temp = [[15,8,17],
//     [12,20,9],
//     [11,7,5]];
var res = [];
 
for(let i=0;i<hu;i++){
    let strings = readLine().split(" ");
    temp[i] = [];
    for(let j=0;j<3;j++){
        temp[i][j] = Number(strings[j]);
    }
}
 
var ints = temp;
 
for(let i=0;i<3;i++){   //从A策略开始遍历
    diaodu(0,i,0);
}
 
res.sort((a,b)=>{
    return a-b;
})
console.log(res[0]);
 
/**
 *
 * @param i 用户
 * @param n 策略 0\1\2 表示为 A\B\C
 * @param count 资源消耗总数
 */
function diaodu( i, n, count){
 
    count += ints[i][n];
    if(i<hu-1){
        i++;
        if(n==0){   //如果此时是A策略
            diaodu(i,1,count);
            diaodu(i,2,count);
        }else if(n==1){
            diaodu(i,0,count);
            diaodu(i,2,count);
        }else {
            diaodu(i,0,count);
            diaodu(i,1,count);
        }
    }else {
        res.push(count);
    }
}

--------------------------
标题：用连续自然数之和来表达整数 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
一个整数可以由连续的自然数之和来表示。给定一个整数，计算该整数有几种连续自然数之和的 表达式 ，且打印出每种表达式。

输入描述:

一个目标整数T (1 <=T<= 1000)

输出描述:

该整数的所有表达式和表达式的个数。如果有多种表达式，输出要求为：

1.自然数个数最少的表达式优先输出

2.每个表达式中按自然数递增的顺序输出，具体的格式参见样例。在每个测试数据结束时，输出一行”Result:X”，其中X是最终的表达式个数。

示例1
输入

9

输出

9=9

9=4+5

9=2+3+4

Result:3

说明

整数 9 有三种表示方法，第1个表达式只有1个自然数，最先输出，第2个表达式有2个自然数，第2次序输出，第3个表达式有3个自然数，最后输出。每个表达式中的自然数都是按递增次序输出的。

数字与符号之间无空格

示例2
输入

10

输出

10=10

10=1+2+3+4

Result:2

解题思路
1、确定取值范围，因为是连续的，所以计算到的最大值为数字的半数左右：

        偶数/2（10计算到5，因为5+6肯定大于10，往后都不用看）

      （奇数+1）/2（9计算到5，因为5+6肯定大于9，往后都不用看）

2、从取值范围的末尾开始往前遍历确定计算最大值，再从最大值往前遍历进行连续值计算和，

      当和等于输入值的时候输出表达式，并计算符合要求的表达式个数，当和大于输入值的时候

      退出此循环进入下一个最大值的计算。（输入值本身也符合要求）

以10为例：

1-5（10/2）为取值范围，从5开始向前遍历

5：5+4+3>10

4：4+3+2+1=10

3：3+2+1<10

2：2+1<10

1：1<10

代码
let n = Number(readLine());
//let n = Number("10");
 
console.log(n+"="+n);    //本身也符合要求
let m ; //连续数字中的最大值
if(n%2==0){
    m = n/2;  //偶数（10计算到5进行了，因为5+6肯定大于10，往后都不用看）
}else {
    m = (n+1)/2;    //奇数（9计算到5进行了，因为5+6肯定大于9，往后都不用看）
}
let count;  //计算和
let res = 1;    //符合要求的表达式个数（本身就算一个）
for(let i=m;i>0;i--){   //从最大值往前推
    count = i;
    let s = String(i);   //将数字字符串化用于拼接
    for(let j=i-1;j>0;j--){
        count+=j;
        s = j+"+"+s;
        if(count==n){
            res++;
            console.log(n+"="+s);
        }else if(count>n){
            break;
        }
    }
}
console.log("Result:"+res);

--------------------------
标题：目录删除 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
某文件系统中有N个目录，每个目录都一个独一无二的ID。每个目录只有一个父目录，但每个父目录下可以有零个或者多个子目录，目录结构呈树状结构。
假设， 根目录 的ID为0，且根目录没有父目录，其他所有目录的ID用唯一的正整数表示，并统一编号。
现给定目录ID和其父目录ID的对应父子关系表[子目录ID，父目录ID]，以及一个待删除的目录ID，请计算并返回一个ID序列，表示因为删除指定目录后剩下的所有目录，返回的ID序列以递增序输出。
注意：
1、被删除的目录或文件编号一定在输入的ID序列中；
2、当一个目录删除时，它所有的子目录都会被删除。

输入描述:

输入的第一行为父子关系表的长度m；接下来的m行为m个父子关系对；最后一行为待删除的ID。序列中的元素以空格分割，参见样例。

输出描述:

输出一个序列，表示因为删除指定目录后，剩余的目录ID。

示例1
输入

5

8 6

10 8

6 0

20 8

2 6

8

输出

2 6

说明

目录结构如下所示：        

     6

   /   \
 2     8
      /  \
     10  20

删除目录8，同时它的子目录10也被删除，剩余2和6两个目录。

解题思路
根据一个目录删除后，其所有的关联子目录都需要删除，我们要想到使用递归。

1、遍历父子关系表，找到需要删除的父目录id所对应的所有子目录id

2、再将步骤1所求得的子目录id作为将要删除的父目录id重复步骤1的操作

3、最后将所有需要删除的id从原集合中剔除（根目录0也需要剔除）

代码
let n = Number(readLine());
//let n = Number("5");
 
let list = [];
var res = "";
var afterDelete = [];
//let test = ["8 6","10 8","6 0","20 8","2 6"]
 
for(let i=0;i<n;i++){
    let ints = readLine().split(" ").map(i=>parseInt(i));
    //let ints = test[i].split(" ").map(i=>parseInt(i));
    if(afterDelete.indexOf(ints[0])==-1){
        afterDelete.push(ints[0]);
    }
    if(afterDelete.indexOf(ints[1])==-1){
        afterDelete.push(ints[1]);
    }
    list.push(ints); //将目录关系表以数组的方式存储在集合中
}
 
let id = Number(readLine());
//let id = Number("8");
let index = afterDelete.indexOf(id);
afterDelete.splice(index,1);
 
deleteMenu(list,id);
 
afterDelete.sort();
 
for(let i=0;i<afterDelete.length;i++){
    if(afterDelete[i]==0){
        continue;
    }
    res+=afterDelete[i];
    if(i!=afterDelete.length-1){
        res+=" ";
    }
}
 
console.log(res);
 
/**
 *
 * @param list  目录关系表集合
 * @param n     需要剔除的目录
 */
function deleteMenu( list, n){
 
    for(let i=0;i<list.length;i++){
        if(list[i][1] == n){    //找到需要剔除的目录的关系数组
            let index = afterDelete.indexOf(list[i][0]);
            afterDelete.splice(index,1);
            delete(list,list[i][0]);
        }
    }
}

--------------------------
标题：相对开音节 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
相对开音节构成的结构为辅音+元音（aeiou）+辅音(r除外)+e，常见的单词有bike、cake等。

给定一个 字符串 ，以空格为分隔符，反转每个单词中的字母，若单词中包含如数字等其他非字母时不进行反转。

反转后计算其中含有相对开音节结构的子串个数（连续的子串中部分字符可以重复）。

输入描述：

字符串，以空格分割的多个单词，字符串长度<10000，字母只考虑小写

输出描述：

含有相对开音节结构的子串个数，注：个数<10000

示例1
输入

ekam a ekac

输出

2

说明

反转后为 make a cake 其中make、cake为相对开音节子串，返回2

示例2
输入

!ekam a ekekac

输出

2

说明

反转后为!ekam a cakeke 因!ekam含非英文字符所以未反转，其中 cake、keke为相对开音节子串，返回2

代码
let s = readLine().split(" ");
//let s = "ekam a ekac".split(" ");
 
let len = s.length;
let count = 0;
 
let reg = new RegExp("^[a-zA-Z]+$");    //全部英文的正则
for(let i=0;i<len;i++){
    let str = s[i];
    let strLen = str.length; //当前字符串长度
    if(strLen<4){    //字符串小于4不符合
        continue;
    }
    if(reg.test(str)){
        str = str.split("").reverse().join("");  //全英文则反转
    }
    for(let j=0;j<=strLen-4;j++){
        if(isKYJ(str.substring(j,j+4))){
            count++;
        }
    }
}
 
console.log(count);
 
function isKYJ(str){
 
    let yuanyin = "aeiou";
    let fuyin = "bcdfghjklmnpqrstvwxyz";
 
    let s1 = str[0];
    let s2 = str[1];
    let s3 = str[2];
    let s4 = str[3];
 
    if(fuyin.indexOf(s1)!=-1    //非元音即辅音
            && yuanyin.indexOf(s2)!=-1
            && fuyin.indexOf(s3)!=-1 && s3!="r"
            && s4=="e") {
        return true;
    }
    return false;
}

--------------------------
标题：矩形相交的面积 | 时间限制：1秒 | 内存 限制：262144K | 语言限制：不限
在坐标系中，给定3个矩形，求相交区域的面积。



输入描述:

3行输入分别为3个矩形的位置，分别代表

‘左上角x坐标’，‘左上角y坐标’，‘矩形宽’，‘矩形高’

-1000 <= x,y < 1000

输出描述:

输出3个矩形相交的面积，不相交的输出0

示例1
输入

1 6 4 4

3 5 3 4

0 3 7 3

输出

2

说明

给定3个矩形A，B，C

A：左上角坐标(1, 6)，宽4，高4

B：左上角坐标(3, 5)，宽3，高4

C：左上角坐标(0, 3)，宽7，高3

3个矩形的相交面积为2，如图所示



解题思路
1、根据输入值，分别计算出三个矩形的上、下、左、右各边界

例如A：上边界：y轴坐标：6

             下边界：y轴坐标 - 高 ：6-4=2

              左边界：x轴坐标：1

              右边界：x轴坐标 + 宽：1+4=5

2、计算面积需要求出宽和高：

        宽：三个矩形的最小右边界 - 三个矩形的最大左边界

        高：三个矩形的最小上边界 - 三个矩形的最大下边界

代码
let a = readLine().split(" ").map(Number);
let b = readLine().split(" ").map(Number);
let c = readLine().split(" ").map(Number);
// let a = "-3 2 4 4".split(" ").map(Number);
// let b = "-1 1 3 4".split(" ").map(Number);
// let c = "-4 -1 7 3".split(" ").map(Number);
// let a = "1 6 2 2".split(" ").map(Number);
// let b = "4 5 2 2".split(" ").map(Number);
// let c = "0 3 7 3".split(" ").map(Number);
 
let top = Math.min(a[1],Math.min(b[1],c[1]));       //上边界为三个坐标Y轴坐标的最小值
let left = Math.max(a[0],Math.max(b[0],c[0]));      //左边界为三个坐标X轴坐标的最大值
let down = Math.max(a[1]-a[3],Math.max(b[1]-b[3],c[1]-c[3]));       //下边界为三个坐标（Y轴坐标-高度）的最大值
let right = Math.min(a[0]+a[2],Math.min(b[0]+b[2],c[0]+c[2]));      //右边界为三个坐标（X轴坐标+宽度）的最小值
 
if(top>down && right>left){
    console.log((top-down)*(right-left));  //高为（上边界-下边界）*宽为（右边界-左边界）
}else {
    console.log(0);
}

--------------------------
标题：矩阵最大值 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
给定一个仅包含0和1的N*N二维矩阵，请计算二维矩阵的最大值，计算规则如下：

1、 每行元素按下标顺序组成一个二进制数（下标越大越排在低位），二进制数的值就是该行的值。矩阵各行值之和为矩阵的值。

2、允许通过向左或向右整体循环移动每行元素来改变各元素在行中的位置。

      比如： [1,0,1,1,1]向右整体循环移动2位变为[1,1,1,0,1]，二进制数为11101，值为29。

                  [1,0,1,1,1]向左整体循环移动2位变为[1,1,1,1,0]，二进制数为11110，值为30。

输入描述:

1、输入的第一行为正整数，记录了N的大小，0 < N <= 20。

2、输入的第2到N+1行为二维矩阵信息， 行内元素 边角逗号分隔。

输出描述:

矩阵的最大值。

示例1
输入

5

1,0,0,0,1

0,0,0,1,1

0,1,0,1,0

1,0,0,1,1

1,0,1,0,1

输出

122

说明

第一行向右整体循环移动1位，得到本行的最大值[1,1,0,0,0]，二进制值为11000，十进制值为24。

第二行向右整体循环移动2位，得到本行的最大值[1,1,0,0,0]，二进制值为11000，十进制值为24。

第三行向左整体循环移动1位，得到本行的最大值[1,0,1,0,0]，二进制值为10100，十进制值为20。

第四行向右整体循环移动2位，得到本行的最大值[1,1,1,0,0]，二进制值为11100，十进制值为28。

第五行向右整体循环移动1位，得到本行的最大值[1,1,0,1,0]，二进制值为11010，十进制值为26。

因此，矩阵的最大值为122。

解题思路
1、通过substring对输入字符串前后段进行分割拼接。

2、通过parseInt对字符串进行 二进制转十进制

代码
let n = Number(readLine());
//let n = Number("5");
let res = 0;
 
// let test = ["1,0,0,0,1",
//             "0,0,0,1,1",
//             "0,1,0,1,0",
//             "1,0,0,1,1",
//             "1,0,1,0,1"]
 
for(let i=0;i<n;i++){
    let s = readLine().replaceAll(",","");   //直接将输入值转换为字符串
    //let s = test[i].replaceAll(",","");
    let max = 0;
    for(let j=0;j<n;j++){
        let newS = s.substring(j) + s.substring(0,j); //字符串分段拼接相当于右移
        max = Math.max(max,parseInt(newS,2));
    }
    res+=max;
}
console.log(res);

--------------------------
标题：磁盘容量排序 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
磁盘的容量单位常用的有M，G，T这三个等级，它们之间的换算关系为1T = 1024G，1G = 1024M，现在给定n块磁盘的容量，请对它们按从小到大的顺序进行 稳定排序 ，例如给定5块盘的容量，1T，20M，3G，10G6T，3M12G9M排序后的结果为20M，3G，3M12G9M，1T，10G6T。注意单位可以重复出现，上述3M12G9M表示的容量即为3M+12G+9M，和12M12G相等。

输入描述:

输入第一行包含一个整数n(2 <= n <= 100)，表示磁盘的个数，接下的n行，每行一个字符串(长度大于2，小于30)，表示磁盘的容量，由一个或多个格式为mv的子串组成，其中m表示容量大小，v表示容量单位，例如20M，1T，30G，10G6T，3M12G9M。

磁盘容量m的范围为1到1024的正整数，容量单位v的范围只包含题目中提到的M，G，T三种，换算关系如题目描述。

输出描述:

输出n行，表示n块磁盘容量排序后的结果。

示例1
输入

3     

1G

2G

1024M

输出

1G

1024M

2G

说明

1G和1024M容量相等，稳定排序要求保留它们原来的相对位置，故1G在1024M之前

示例2
输入

3

2G4M

3M2G

1T

输出

3M2G

2G4M

1T

说明

1T的容量大于2G4M，2G4M的容量大于3M2G

解题思路
1、需要将所有的磁盘容量转换成最小单位M

2、使用二维数组记录磁盘索引和磁盘转换成M单位的数值

3、使用Map记录磁盘索引和磁盘容量原数值

4、对二维数组进行排序，最后根据索引输出磁盘容量原数值

代码
let n = Number(readLine());
//let n = Number("3");
 
let num = [];    //用来放置磁盘索引和单位转换成M之后的数值
let map = []; //用来放置磁盘索引和磁盘原数值
//let strs = ["1G","2G","1024M"];
 
for (let i = 0; i < n; i++) {
    let sum = 0;
    let index = -1;
    let str = readLine();
    //let str = strs[i];
    map[i + 1] = str;
    for (let j = 0; j < str.length; j++) {
        if (str.charAt(j) == 'M') {
            sum += Number(str.substring(index + 1, j));
            index = j;
        } else if (str.charAt(j) == 'G') {
            sum += Number(str.substring(index + 1, j)) * 1024;
            index = j;
        } else if (str.charAt(j) == 'T') {
            sum += Number(str.substring(index + 1, j)) * 1024 * 1024;
            index = j;
        }
    }
    num[i] = [];
    num[i][0] = i + 1;
    num[i][1] = sum;
 
}
 
num.sort((a,b)=>{
    return a[1]-b[1];
});  //对二维数组进行排序
 
for (let i = 0; i < n; i++) {
    console.log(map[num[i][0]]);
}

--------------------------
标题：竖直四子棋 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
竖直四子棋的棋盘是竖立起来的，双方轮流选择棋盘的一列下子，棋子因重力落到棋盘底部或者其他棋子之上，当一列的棋子放满时，无法再在这列上下子。

一方的4个棋子横、竖或者斜方向连成一线时获胜。现给定一个棋盘和红蓝对弈双方的下子步骤，判断红方或蓝方是否在某一步获胜。

下面以一个6x5的棋盘图示说明落子过程：

8eb0b2e51025330e5ceb0301b0a998e5.png

下面给出横、竖和斜方向四子连线的图示：

6aadc2df4989bdf85f83476550aa9fbb.png

输入描述:

输入为2行，第一行指定棋盘的宽和高，为空格分隔的两个数字；第二行依次间隔指定红蓝双方的落子步骤，第1步为红方的落子，第2步为蓝方的落子，第3步为红方的落子，以此类推。
步骤由空格分隔的一组数字表示，每个数字为落子的列的编号（最左边的列编号为1，往右递增）。用例保证数字均为32位有符号数。

输出描述:

如果落子过程中红方获胜，输出 N,red ；如果落子过程中蓝方获胜，输出 N,blue ；如果出现非法的落子步骤，输出 N,error。N为落子步骤的序号，从1开始。如果双方都没有获胜，输出 0,draw 。
非法落子步骤有两种，一是列的编号超过棋盘范围，二是在一个已经落满子的列上落子。N和单词red、blue、draw、error之间是英文逗号连接。

示例1
输入

5 5

1 1 2 2 3 3 4 4

输出

7,red

说明

在第7步，红方在第4列落下一子后，红方的四个子在第一行连成一线，故红方获胜，输出 7,red

示例2
输入

5 5

0 1 2 2 3 3 4 4

输出

1,error

说明

第1步的列序号为0，超出有效列编号的范围，故输出 1,error

解题思路
1、根据输入的宽和高，构建对应的二维数组（全为0）

2、因为是四子棋，所以到第七个棋子才能取判断。（小于七个都不符合）

代码
/**
 * 6 5
 * 2 3 2 4 2 5 3 4 4 2 6 3
 */
let nums = readLine().split(" ").map(Number);
let strings = readLine().split(" ").map(Number);
// let nums = "6 5".split(" ").map(Number);
// let strings = "1 1 2 2 3 3 4 4".split(" ").map(Number);
 
var m = nums[0];
var n = nums[1];
 
let ints = Array(n).fill().map(()=>Array(m).fill(0));
let isOver = false;
for (let i=0;i<strings.length;i++){
    let index = -1;
    let color = 1;
    let num = strings[i];
    if(num<=0 || num>m || ints[0][num-1]!=0){
        isOver = true;
        console.log(i+1+",error");
        break;
    }
    if(i%2!=0){ //偶数下标为red，用1表示
        color = 2;  //奇数下标为blue，用2表示
    }
    for(let j=n-1;j>=0;j--){
        if(ints[j][num-1]==0){
            index = j;  //此时棋子横坐标为j，纵坐标为num-1
            ints[j][num-1] = color;
            break;
        }
    }
    if(index==-1){
        System.out.println(i+1+",error");
        isOver = true;
        break;
    }
    if(i>=6 && 
        (isZongXiang(ints,index,num-1)
        || isHengXiang(ints,index,num-1)
        || isZuoXie(ints,index,num-1)
        || isYouXie(ints,index,num-1))){   //第七个棋子才开始符合四棋子的要求
        if(color==1){
            console.log(i+1+",red");
            isOver = true;
            break;
        }else {
            console.log(i+1+",blue");
            isOver = true;
            break;
        }
    }
}
if(!isOver){
    console.log("0,draw");
}
 
/**
 *  纵向四子
 */
function isZongXiang( ints, x, y){
 
    if(x < n-3){
        let jishu = 3;
        while (jishu>0 && ints[x][y] == ints[++x][y]){
            jishu--;
        }
        if(jishu==0){
            return true;
        }
    }
    return false;
}
 
/**
 *  横向四子
 */
function isHengXiang( ints, x, y){
 
    let jishu = 3;
    let a = x;
    let b = y;
    while (jishu>0 && b>0 && ints[a][b] == ints[a][--b]){
        jishu--;
    }
    while (jishu>0 && y<m-1 && ints[x][y] == ints[x][++y]){
        jishu--;
    }
    if(jishu==0){
        return true;
    }
 
    return false;
}
 
/**
 *  左边斜向四子
 */
function isZuoXie( ints, x, y){
 
    let jishu = 3;
    let a = x;
    let b = y;
    while (jishu>0 && (a<n-1 && b>0) && ints[a][b] == ints[++a][--b]){ //左下
        jishu--;
    }
    while (jishu>0 && (x>0 && y<m-1) && ints[x][y] == ints[--x][++y]){   //右上
        jishu--;
    }
    if(jishu==0){
        return true;
    }
 
    return false;
}
 
/**
 *  右边斜向四子
 */
function isYouXie( ints, x, y){
 
    let jishu = 3;
    let a = x;
    let b = y;
    while (jishu>0 && (a<n-1 && b<m-1) && ints[a][b] == ints[++a][++b]){ //右下
        jishu--;
    }
    while (jishu>0 && (x>0 && y>0) && ints[x][y] == ints[--x][--y]){   //左上
        jishu--;
    }
    if(jishu==0){
        return true;
    }
 
    return false;
}

--------------------------
标题：第k个排列 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定参数n，从1到n会有n个整数：1,2,3,…,n，这n个数字共有 n! 种排列。
按大小顺序升序列出所有排列情况，并一一标记，当 n = 3 时, 所有排列如下：
"123"
"132"
"213"
"231"
"312"
"321"
给定 n 和 k，返回第 k 个排列。

输入描述:

输入两行，第一行为n，第二行为k，给定 n 的范围是 [1,9]，给定 k 的范围是[1,n!]。

输出描述:

输出排在第k位置的数字。

示例1
输入

3

3

输出

213

说明

3的排列有123 132 213...，那么第3位置的为213

示例2
输入

2

2

输出

21

说明

2的排列有12 21，那么第2位置的为21

解题思路
对输入的n个连续正整数进行 全排列 。（非常经典的全排列算法，大家要记一下）

代码
let n = Number(readLine());
let k = Number(readLine());
// let n = Number("3");
// let k = Number("3");
 
var list = [];
let ints = [];
for(let i=0;i<n;i++){
    ints[i] = i+1;
}
 
/**
 * cursor:从第一个数开始
 */
fullArray(ints,0,n-1);
 
list.sort((a,b)=>{  //对list进行升序排序
    return b>a ? -1: 1;
});
 
console.log(list[k-1]);
 
function swap( arr, a, b){
    let temp = arr[a];
    arr[a] = arr[b];
    arr[b] = temp;
}
 
/**
 * 这是经典的全排列递归算法
 * @param array 需要排列的数组
 * @param cursor  初始位置
 * @param end   结束位置
 */
function fullArray(array, cursor, end) {
    if (cursor == end) {    //此次排列完成
        let s = "";
        for (let a of array) {
            s+=a;
        }
        list.push(Number(s));
    } else {
        for (let i = cursor; i <= end; i++) {
            swap(array, cursor, i); //将数组下标为cursor和下标为i的数据进行交换
            fullArray(array, cursor + 1, end);
            swap(array, cursor, i); // 用于对之前交换过的数据进行还原
        }
    }
}

--------------------------
标题：篮球比赛 | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
篮球（5V5）比赛中，每个球员拥有一个战斗力，每个队伍的所有球员战斗力之和为该队伍的总体战斗力。现有10个球员准备分为两队进行训练赛，教练希望2个队伍的战斗力差值能够尽可能的小，以达到最佳训练效果。给出10个球员的战斗力，如果你是教练，你该如何分队，才能达到最佳训练效果？请输出该分队方案下的最小战斗力差值。

输入描述:

10个篮球队员的战斗力（整数，范围[1,10000]），战斗力之间用空格分隔，如：10 9 8 7 6 5 4 3 2 1

不需要考虑异常输入的场景。

输出描述:

最小的战斗力差值，如：1

示例1
输入

10 9 8 7 6 5 4 3 2 1

输出

1

说明

1 2 5 9 10分为一队，3 4 6 7 8分为一队，两队战斗力之差最小，输出差值1。备注：球员分队方案不唯一，但最小战斗力差值固定是1

解题思路
因为题目确定了是10个队员分两队，也就是每个队5个人，我们可以先固定前四个队员，接着遍历剩下的六名选择其中一个队员为一队，剩下5人为二队，计算两队战力并求差。然后固定前三个队员+第五位队员，接着遍历后面的五位队员选择其中一个队员为一队，剩下5人为二队，计算两队战力并求差。。。。最后求差值的最小值

代码
let people = readLine().split(" ").map(i=>parseInt(i));
//let people = "10 9 8 7 6 5 4 3 2 1".split(" ").map(i=>parseInt(i));
 
let count = 0;  //总队员战力
for(let i=0;i<10;i++){
    count+=people[i];
}
let n ;
let min = Number.MAX_VALUE;
for(let i=0;i<6;i++){
    for(let j=i+1;j<7;j++){
        for(let k=j+1;k<8;k++){
            for(let l=k+1;l<9;l++){
                for(let m=l+1;m<10;m++){
                    n = people[i] + people[j] + people[k] + people[l] + people[m];
                    min = Math.min(min, Math.abs(count-2*n));
                }
            }
        }
    }
}
console.log(min);

--------------------------
标题：素数之积 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
RSA加密算法 在网络安全世界中无处不在，它利用了极大整数因数分解的困难度，数据越大，安全系数越高，给定一个32位正整数，请对其进行因数分解，找出是哪两个素数的乘积。

输入描述:

一个正整数num

0 < num <= 2147483647

输出描述:

如果成功找到，以单个空格分割，从小到大输出两个素数，分解失败，请输出-1 -1

示例1
输入

15

输出

3 5

说明

因数分解后，找到两个素数3和5，使得3*5=15，按从小到大排列后，输出3 5

示例2
输入

27

输出

-1 -1

说明

通过因数分解，找不到任何素数，使得他们的乘积为27，输出-1 -1

解题思路
        素数：只有1和本身两个约数。对输入值进行分解因子，只有2个因子的符合，其他的都输出-1 -1

代码
let n = Number(readLine());
//let n = Number("15");
 
let list = [];
let m = 0;
/**
 * 本题就是求出一个数只有两个因子（1不是素数）
 * 遍历n求出它所有的因子
 */
while (m!=n){   //当n==m时说明已经不能再除了，跳出循环
    n = m!=0? m: n;
    for(let i=2;i<Math.sqrt(n)+1;i++){
        if(n%i==0){
            m = n/i;    //把商作为下次的被除数
            list.push(i);    //i就是因子
            break;
        }
    }
}
 
list.push(m);
 
if(list.length==2){
    console.log(list[0]+" "+list[1]);
}else {
    console.log("-1 -1");
}

--------------------------
标题：组成最大数 | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
小组中每位都有一张卡片，卡片上是6位内的正整数，将卡片连起来可以组成多种数字，计算组成的最大数字。

输入描述:

“,”号分割的多个正整数字符串，不需要考虑非数字异常情况，小组最多25个人

输出描述:

最大的数字字符串

示例1
输入

22,221

输出

22221

示例2
输入

4589,101,41425,9999

输出

9999458941425101

解题思路
题目极限是需要对25个6位数进行拼接，所以进行 全排列 肯定是不能的。

转变思想就是进行 冒泡算法 ，然后按照降序拼接（比较难懂，但是解法没有问题通过100%）

代码
let str = readLine().split(",");
//let str = "4589,101,41425,9999".split(",");
let len = str.length;
 
/**
 * 经典冒泡算法
 */
for(let i=0;i<len;i++){
    for(let j=i+1;j<len;j++){
        if(Number(str[i]+str[j]) < Number(str[j]+str[i])){
            let temp = str[i];
            str[i] = str[j];
            str[j] = temp;
        }
    }
}
 
let res = "";
for(let i=0;i<len;i++){
    res+=str[i];
}
 
console.log(res);

--------------------------
标题：统计射击比赛成绩 | 时间限制：1秒 | 内存限制：65536K | 语言限制：不限
给定一个射击比赛成绩单，包含多个选手若干次射击的成绩分数，请对每个选手按其最高3个分数之和进行降序排名，输出降序排名后的选手ID序列。条件如下：

1、一个选手可以有多个射击成绩的分数，且次序不固定。

2、如果一个选手成绩少于3个，则认为选手的所有成绩无效，排名忽略该选手。

3、如果选手的成绩之和相等，则成绩之和相等的选手按照其ID 降序排列 。

输入描述:

输入第一行，一个整数N，表示该场比赛总共进行了N次射击，产生N个成绩分数（2<=N<=100）。

输入第二行，一个长度为N整数序列，表示参与每次射击的选手ID（0<=ID<=99）。

输入第三行，一个长度为N整数序列，表示参与每次射击的选手对应的成绩（0<=成绩<=100）。

输出描述:

符合题设条件的降序排名后的选手ID序列。

示例1
输入

13

3,3,7,4,4,4,4,7,7,3,5,5,5

53,80,68,24,39,76,66,16,100,55,53,80,55

输出

5,3,7,4

说明

该场射击比赛进行了13次，参赛的选手为{3,4,5,7}。

3号选手成绩：53,80,55，最高3个成绩的和为：80+55+53=188。

4号选手成绩：24,39,76,66，最高3个成绩的和为：76+66+39=181。

5号选手成绩：53,80,55，最高3个成绩的和为：80+55+53=188。

7号选手成绩：68,16,100，最高3个成绩的和为：100+68+16=184。

比较各个选手最高3个成绩的和，有3号=5号>7号>4号，由于3号和5号成绩相等且ID号5>3，所以输出为：5,3,7,4

代码
let n = Number(readLine());
let s1 = readLine().split(","); //队员
let s2 = readLine().split(","); //射击成绩
 
// let n = Number("13");
// let s1 = "3,3,7,4,4,4,4,7,7,3,5,5,5".split(","); //队员
// let s2 = "53,80,68,24,39,76,66,16,100,55,53,80,55".split(","); //射击成绩
 
let map = {}    //将队员和射击成绩放入map对象中
 
/**
 * 队员作为key值，成绩作为value值（集合）
 */
for(let i=0;i<n;i++){
    let key = Number(s1[i]);
    let value = Number(s2[i]);
    if(map[key]){
        map[key].push(value);
    }else {
        let list = [];
        list.push(value);
        map[key] = list;
    }
}
/**
 * 将队员id及最高三个成绩之和放入集合list
 */
var scoreLists = [];
 
for(var key in map){
    let len = map[key].length;
    if(len>=3){
        let list = [];  //将所有队员数据放在集合scoreLists
        map[key].sort();    //对成绩进行排序并计算三个最高成绩和
        list.push(key);
        list.push(map[key][len-1] + map[key][len-2] + map[key][len-3]);
        scoreLists.push(list);
    }
}
 
scoreLists.sort((a,b)=>{
    if(b[1]>a[1]){  //成绩高的在前
        return 1;
    }
    if(b[1]==a[1] && b[0]>a[0]){  //成绩相等时，id高的在前
        return 1;
    }
    return -1;
});
 
let res = "";
let scoListsLen = scoreLists.length;
for(let i=0;i < scoListsLen - 1;i++){
    res+=scoreLists[i][0]+",";   //各队员成绩的第一个数为其id
}
console.log(res+scoreLists[scoListsLen-1][0]);

--------------------------
标题：考古学家 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
有一个考古学家发现一个石碑，但是很可惜，发现时其已经断成多段，原地发现n个断口整齐的石碑碎片。为了破解石碑内容，考古学家希望有程序能帮忙计算复原后的石碑文字 组合数 ，你能帮忙吗？

输入描述:

第一行输入n，n表示石碑碎片的个数。

第二行依次输入石碑碎片上的文字内容s，共有n组。    

输出描述:

输出石碑文字的组合（按照 升序排列 ），行末无多余空格。

示例1
输入

3

a b c

输出

abc

acb

bac

bca

cab

cba

说明

当石碑碎片上的内容为“a”，“b”，“c”时，则组合有“abc”，“acb”，“bac”，“bca”，“cab”，“cba”

示例2
输入

3

a b a

输出

aab

aba

baa

说明

当石碑碎片上的内容为“a”，“b”，“a”时，则可能的组合有“aab”，“aba”，“baa”

示例3
输入

3

a b ab

输出

aabb

abab

abba

baab

baba

说明

当石碑碎片上的内容为“a”，“b”，“ab”时，则可能的组合有“aabb”，“abab”，“abba”，“baab”，“baba”

备注:

如果存在石碑碎片内容完全相同，则由于碎片间的顺序变换不影响复原后的碑文内容，即相同碎片间的位置变换不影响组合。

解题思路
全排列之后去重。

代码
// let n = Number(readline());
// let strs = readline().split(" ");
let n = Number("3");
let strs = "a b ab".split(" ");
 
var list = [];
 
fullArray(strs, 0 , n-1);
list.sort();
 
for(let i=0; i<list.length; i++){
    console.log(list[i]);
}
 
function sawp( strings, a, b){
 
    let temp = strings[a];
    strings[a] = strings[b];
    strings[b] = temp;
 
}
 
function fullArray( strings, start, end){
 
    if(start == end){
        let s = "";
        for (let a of strings) {
            s += a;
        }
        if(!list.includes(s)){
            list.push(s)
        };
    }else {
        for(let i=start; i<=end; i++){
            sawp(strings, start, i);
            fullArray(strings, start+1, end);
            sawp(strings, start, i);
        }
    }
}

--------------------------
标题：英文输入法 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
主管期望你来实现英文 输入法 单词联想功能。需求如下：

依据用户输入的单词前缀，从已输入的英文语句中联想出用户想输入的单词，按 字典序 输出联想到的单词序列，如果联想不到，请输出用户输入的单词前缀。

注意：

1.  英文单词联想时，区分大小写

2.  缩略形式如”don't”，判定为两个单词，”don”和”t”

3.  输出的单词序列，不能有重复单词，且只能是英文单词，不能有标点符号

输入描述:

输入为两行。

首行输入一段由英文单词word和标点符号组成的语句str；

接下来一行为一个英文单词前缀pre。

0 < word.length() <= 20

0 < str.length <= 10000

0 < pre <= 20

输出描述:

输出符合要求的单词序列或单词前缀，存在多个时，单词之间以单个空格分割

示例1
输入

I love you

He

输出

He

说明

从用户已输入英文语句”I love you”中提炼出“I”、“love”、“you”三个单词，接下来用户输入“He”，从已输入信息中无法联想到任何符合要求的单词，因此输出用户输入的单词前缀。

示例2
输入

The furthest distance in the world, Is not between life and death, But when I stand in front of you, Yet you don't know that I love you.

f

输出

front furthest

说明

从用户已输入英文语句”The furthestdistance in the world, Is not between life and death, But when I stand in frontof you, Yet you dont know that I love you.”中提炼出的单词，符合“f”作为前缀的，有“furthest”和“front”，按 字典序排序 并在单词间添加空格后输出，结果为“frontfurthest”。

代码
// let strings = readline()
//         .replace("'"," ")   //对“'”符号进行空格处理
//         .replace(",","")    
//         .replace(".","")
//         .replace("?","")
//         .replace("!","")    //对“, . ? !”符号进行删除处理
//         .split(" ");    //按照空格进行分割
let strings = "The furthest distance in the world, Is not between life and death, But when I stand in front of you, Yet you don't know that I love you."
        .replace("'"," ")   //对“'”符号进行空格处理
        .replace(",","")    
        .replace(".","")
        .replace("?","")
        .replace("!","")    //对“, . ? !”符号进行删除处理
        .split(" ");    //按照空格进行分割
 
strings.sort();   //因为是字典需要进行排序
//let key = readline();
let key = "f";
let keyLen = key.length;
let strLen = strings.length;
let res = "";
 
for(let i=0; i<strLen; i++){
    let s = strings[i];
    if(s.length >= keyLen && s.substring(0,keyLen) == key){    //匹配的字符串需要判断长度，并进行关键词长度的分割
        if(res.indexOf(s)!=-1){
            continue;
        }
        if(res.length != 0){
            res += " ";
        }
        res += s;
    }
}
if(res.length == 0){
    res = key;
}
console.log(res);

--------------------------
标题：补种未成活胡杨 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
近些年来，我国防沙治沙取得显著成果。某沙漠新种植N棵胡杨（编号1-N），排成一排。一个月后，有M棵胡杨未能成活。

现可补种胡杨K棵，请问如何补种（只能补种，不能新种），可以得到最多的连续胡杨树？

输入描述:

N 总种植数量

M 未成活胡杨数量

M 个空格分隔的数，按编号从小到大排列
K 最多可以补种的数量

其中：

1<=N<=100000

1<=M<=N

0<=K<=M

输出描述:

最多的连续胡杨棵树

示例1
输入

5

2

2 4

1

输出

3

说明

补种到2或4结果一样，最多的连续胡杨棵树都是3

示例2
输入

10

3

2 4 7

1

输出

6

说明

补种第7棵树，最多的连续胡杨棵树为6(5,6,7,8,9,10)

解题思路
1、根据题意需要获取最多的连续胡杨树，则补种的胡杨需要时相邻的

        例：10棵胡杨 4棵死亡 2，3，6，8  可以补种2棵

        则应该是2，3 / 3，6 / 6，8这样补种才会最多

        2，3 ： 连续胡杨  6（未成活） -1 = 5

        3，6 ： 连续胡杨 8（未成活）-2（未成活）-1 = 5

        6，8 ： 连续胡杨10（总数目）-3（未成活）= 7

由此可以对未成活的胡杨进行遍历补种。

代码
let n = Number(readLine());   //总共棵树
let m = Number(readLine());   //未成活的棵树
let dead = readLine().split(" ").map(i=>parseInt(i));   //未成活的数
let k = Number(readLine()); //补种的棵树
// let n = Number("10");   //总共棵树
// let m = Number("3");   //未成活的棵树
// let dead = "2 4 7".split(" ").map(i=>parseInt(i));   //未成活的数
// let k = Number("1"); //补种的棵树
 
let max = 0;
 
for(let i=k-1;i<m;i++){ //i为补种的最后一棵胡杨下标
    if(i==k-1){
        max = Math.max(max,dead[k]-1);  //种最前面的k棵树
    }else if(i==m-1){
        max = Math.max(max,n-dead[i-k]);  //种最后面的k棵树
    }else {
        max = Math.max(max,dead[i+1]-dead[i-k]-1);  //种中间的k棵树
    }
}
 
console.log(max);

--------------------------
标题：解压报文 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
为了提升数据传输的效率，会对传输的报文进行压缩处理。输入一个压缩后的报文，请返回它解压后的原始报文。

压缩规则：n[str]，表示方括号内部的 str 正好重复 n 次。注意 n 为正整数（0 < n <= 100），str只包含小写英文字母，不考虑异常情况。

输入描述:

输入压缩后的报文：

1）不考虑无效的输入，报文没有额外的空格，方括号总是符合格式要求的；

2）原始报文不包含数字，所有的数字只表示重复的次数 n ，例如不会出现像 5b 或 3[8] 的输入；

输出描述:

解压后的原始报文

注：

1）原始报文长度不会超过1000，不考虑异常的情况

示例1
输入

3[k]2[mn]

输出

kkkmnmn

说明

k 重复3次，mn 重复2次，最终得到 kkkmnmn

示例2
输入

3[m2[c]]

输出

mccmccmcc

说明

m2[c] 解压缩后为 mcc，重复三次为 mccmccmcc

解题思路
当碰到“]”的时候，取出队列最上层的数字和字母，进行解压
再将步骤2解压出的字符与字母队列中最上层的字符进行拼接，用于下次解压（因为括号里面的所有字符都受前面数字控制解压，所有需要拼接）
重复步骤1，直至遍历完整个字符串
代码
let s = readLine();
//let s = "3[m2[c]]";
let res = "";  //处理前的字母串
let numStr = "";  //处理多位数
let num = [];    //数字队列
let zimu = [];  //放置处理后的字母串
for(let i=0;i<s.length;i++){
    let c = s.charAt(i);
    if(!isNaN(Number(c))){  //判断是否为数字
        if(res.length!=0){    //数字前的字母暂不处理
            zimu.push(res);
            res = "";
        }
        numStr += c;
    }else if(c=='['){
        num.push(Number(numStr));  //数字放入数字队列
        numStr = "";
    }else if(c==']'){
        let n = num.pop();  //碰到“]”，就需要取出最上面的数字进行解压
        if(res.length!=0){
            zimu.push(res);
            res = "";
        }
        let temp = zimu.pop(); //取出最上面的字母
        let sb = "";
        for(let j=0;j<n;j++){
            sb+=temp;    //对字母进行解压
        }
        if(zimu.length==0){
            zimu.push(sb);
        }else {
            zimu.push(zimu.pop()+sb);   //后面处理过的字符会跟最上面的字符一起被处理
        }
    }else {
        res+=c;
    }
}
console.log(zimu);

--------------------------
标题：解密犯罪时间 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
警察在侦破一个案件时，得到了线人给出的可能犯罪时间，形如 “HH:MM” 表示的时刻。

根据警察和线人的约定，为了隐蔽，该时间是修改过的，解密规则为：利用当前出现过的数字，构造下一个距离当前时间最近的时刻，则该时间为可能的犯罪时间。每个出现数字都可以被无限次使用。

输入描述:

形如HH:SS的 字符串 ，表示原始输入

输出描述:

形如HH:SS的字符串，表示推理出来的犯罪时间

示例1
输入

18:52

输出

18:55

说明

利用数字1, 8, 5, 2构造出来的最近时刻是18:55，是3分钟之后。结果不是18:51因为这个时刻是23小时59分钟之后。

示例2
输入

23:59

输出

22:22

说明

利用数字2, 3, 5, 9构造出来的最近时刻是22:22。 答案一定是第二天的某一时刻，所以选择可构造的最小时刻为犯罪时间。

备注:

1.    可以保证线人给定的字符串一定是合法的。例如，“01:35” 和 “11:08” 是合法的，“1:35” 和 “11:8” 是不合法的。

2.    最近的时刻有可能在第二天。

解题思路
根据题意可以判断时间都是由四个数字组成，把时间各数取出放入按序放入数组中
把四个数进行全遍历，获取所有可能的时间（必须符合时间格式要求），并跟错误时间进行比较。分别取出大于错误时间的最小值和小于错误时间的最小值。
如果存在大于错误时间的最小值，则最小值为犯罪时间；若不存在，小于错误时间的最小值为犯罪时间
代码
let s = readLine();
//let s = "18:52";
let errorTime = Number(s.substring(0,2)+s.substring(3));
let num = [];
num[0] = s.charAt(0);
num[1] = s.charAt(1);
num[2] = s.charAt(3);
num[3] = s.charAt(4);
let time;
let min = Number.MAX_VALUE;    //小于错误时间的最小时间（第二天）
let minThan = Number.MAX_VALUE;    //大于错误时间的最小时间
for(let i=0;i<4;i++){
    if(Number(num[i])>2){ //首位不能大于2
        continue;
    }
    for(let j=0;j<4;j++){
        if(Number(num[i])==2 && Number(num[j])>3){  //第一位为2时第二位则不能大于3
            continue;
        }
        for(let k=0;k<4;k++){
            if(Number(num[k])>6){ //第三位不能大于6
                continue;
            }
            for(let l=0;l<4;l++){
                time = Number(num[i]+num[j]+num[k]+num[l]);   //重构的时间
                if(time<errorTime){
                    min = Math.min(min,time);
                }else if(time>errorTime){
                    minThan = Math.min(minThan,time);
                }
            }
        }
    }
}
let res = "";
if(minThan == Number.MAX_VALUE){ //若重构的时间都小于错误时间，则时间为第二天时间
    res = String(min);
}else {
    res = String(minThan);
}
console.log(res.substring(0,2)+":"+res.substring(2));

--------------------------
标题：计算堆栈中的剩余数字 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
向一个空栈中依次存入正整数， 假设入栈元素n(1<=n<=2^31-1)按顺序依次为nx...n4、n3、n2、n1, 每当元素入栈时，如果n1=n2+...+ny(y的范围[2,x]，1<=x<=1000)，则n1~ny全部元素出栈，重新入栈新元素m(m=2*n1)。

如：依次向栈存入6、1、2、3, 当存入6、1、2时，栈底至栈顶依次为[6、1、2]；当存入3时，3=2+1，3、2、1全部出栈，重新入栈元素6(6=2*3)，此时栈中有元素6；因为6=6，所以两个6全部出栈，存入12，最终栈中只剩一个元素12。

输入描述:

使用单个空格隔开的正整数的字符串，如"5 6 7 8"， 左边的数字先入栈，输入的正整数个数为x，1<=x<=1000。

输出描述:

最终栈中存留的元素值，元素值使用空格隔开，如"8 7 6 5"， 栈顶数字在左边。

示例1
输入

5 10 20 50 85 1

输出

1 170

说明

5+10+20+50=85， 输入85时，5、10、20、50、85全部出栈，入栈170，最终依次出栈的数字为1和170。

示例2
输入

6 7 8 13 9

输出

9 13 8 7 6

示例3
输入

1 2 5 7 9 1 2 2

输出

4 1 9 14 1

代码
//let numList = readline().split(" ").map(Number);
//let numList = "5 10 20 50 85 1".split(" ").map(Number);
let numList = "1 2 5 7 9 1 2 2".split(" ").map(Number);
 
let len = numList.length;
let isChange = true;    //判断集合是否变化，初始化为true
 
while (numList.length!=1 && (isChange)){   //当集合长度不为1且有变化的时候进入循环
    for(let i=1; i<numList.length; i++){
        let n = i;
        let num = numList[i];  //第i个数num
        let isEnd = false;
        let count = 0;
        while (!isEnd){
            n--;
            count += numList[n];   //遍历求前i-1到n的和count
            if(count == num){
                numList.splice(n, i+1-n, 2*num);  //在下标为n的地方添加2*num，并删除i-n+1长度的字符
                isEnd = true;   //表示结束了，可以跳出本次循环了
                isChange = true;    //防止上一轮ischange被置反，所以再次赋值为true
                break;  //跳出循环
            }
            if(count>num || n==0){   //count已经大于num或者已经遍历到第一个数了
                isEnd = true;  //表示结束了，可以跳出本次循环了
                isChange = false;   //没有变化的值
            }
        }
        if(isChange){   //当有变化的值的时候需要推出for循环重新进入while循环
            break;
        }
    }
}
 
let res = "";
for(let i=numList.length-1; i>=0; i--){
    res += numList[i]; //将数据进行逆向输出
    if(i!=0){
        res+=" ";
    }
}
 
console.log(res);

--------------------------
标题：计算疫情扩散时间 | 时间限制：1秒 | 内存限制：32768K | 语言限制：不限
在一个地图中(地图由n*n个区域组成），有部分区域被感染病菌。感染区域每天都会把周围（上下左右）的4个区域感染。

请根据给定的地图计算，多少天以后，全部区域都会被感染。

如果初始地图上所有区域全部都被感染，或者没有被感染区域，返回-1

输入描述:

一行N*N个数字（只包含0,1，不会有其他数字）表示一个地图，数字间用,分割，0表示未感染区域，1表示已经感染区域

每N个数字表示地图中一行，输入数据共表示N行N列的区域地图。

例如输入1,0,1,0,0,0,1,0,1，表示地图

1,0,1

0,0,0

1,0,1

输出描述:

一个整数，表示经过多少天以后，全部区域都被感染

示例1
输入

1,0,1,0,0,0,1,0,1

输出

2

说明

1天以后，地图中仅剩余中心点未被感染；2天以后，全部被感染。

示例2
输入

0,0,0,0

输出

-1

说明

无感染区域

示例3
输入

1,1,1,1,1,1,1,1,1

输出

-1

说明

全部都感染

备注:

1<=N<200

解题思路
1、根据输入的数字长度计算出二维数组的长和宽（长度 开方 ）

2、根据输入的0和1，整理出二维数组，并找出未被感染的区域，放入集合中

3、遍历未被感染的坐标集合，判断是否被感染（上下左右如果有一个是疫情区域，则被感染）。若被感染，则放入被感染的区域集合中。

4、从未被感染的集合中剔除被感染的区域，重复步骤3，直至全部被感染。

代码
let strs = readLine().split(",").map(Number);
//let strs = "1,0,1,0,0,0,1,0,1".split(",").map(Number);
 
var N = Math.sqrt(strs.length);   //总数开方为二维数组长宽
let n = 0;
let list = [];   //未被感染的区域
var ints = [];
 
for(let i=0;i<N;i++){
    ints[i] = [];
    for(let j=0;j<N;j++){
        let x = strs[n++];
        ints[i][j] = x;
        if(x==0){
            let temp = [];
            temp[0] = i;
            temp[1] = j;
            list.push(temp);
        }
    }
}
 
if(list.length==0 || list.length==strs.length){ //全部感染或者全部安全
    console.log(-1);
}else {
    let res = 0;    //天数
    let sickList = [];   //被传染的区域集合
 
    while (list.length!=0){
        res++;
 
        //被传染的区域需要置为1
        for(let i=0; i<sickList.length; i++){
            let temp = sickList[i];
            ints[temp[0]][temp[1]] = 1;
        }
        sickList = [];
 
        for(let i=0; i<list.length; i++){
            let temp = list[i];
            if(chuanran(temp[0],temp[1])){  //会被感染
                sickList.push(temp);
            }
        }
 
        list = list.filter(e=>!sickList.includes(e));   //从未被感染的区域中剔除被传染的区域
    }
 
    console.log(res);
}
/**
 *
 * @param x 横坐标
 * @param y 纵坐标
 * @return  是否会被传染
 */
function chuanran( x,  y){
 
    //上
    if(x>0 && ints[x-1][y] == 1){
        return true;
    }
    //下
    if(x<N-1 && ints[x+1][y] == 1){
        return true;
    }
    //左
    if(y>0 && ints[x][y-1] == 1){
        return true;
    }
    //右
    if(y<N-1 && ints[x][y+1] == 1){
        return true;
    }
 
    return false;
}

--------------------------
标题：计算面积 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
绘图机器的绘图笔初始位置在原点（0, 0），机器启动后其绘图笔按下面规则绘制直线：
1）尝试沿着横向坐标轴正向绘制直线，直到给定的终点值E。
2）期间可通过指令在纵坐标轴方向进行偏移，并同时绘制直线，偏移后按规则1 绘制直线；指令的格式为X offsetY，表示在横坐标X 沿纵坐标方向偏移，offsetY为正数表示正向偏移，为负数表示负向偏移。

给定了横坐标终点值E、以及若干条绘制指令，请计算绘制的直线和横坐标轴、以及 X=E 的直线组成图形的面积。

输入描述:

首行为两个整数 N E，表示有N条指令，机器运行的横坐标终点值E。
接下来N行，每行两个整数表示一条绘制指令X offsetY，用例保证横坐标X以递增排序方式出现，且不会出现相同横坐标X。
取值范围：0 < N <= 10000, 0 <= X <= E <=20000, -10000 <= offsetY <= 10000。

输出描述:

一个整数，表示计算得到的面积，用例保证，结果范围在0~4294967295内

示例1
输入

4 10

1 1

2 1

3 1

4 -2

输出

12

说明

通过操作机器最后绘制了如下图形（蓝色为绘制笔绘制的直线）


计算图 中阴影部分面积，其值为1*1+2*1+3*1+1*6=12

示例2
输入

2 4

0 1

2 -2

输出

4

说明

通过操作机器最后绘制了如下图形



计算图中阴影部分面积，其值为1*2+1*2=4

解题思路
N E

a1 b1

a2 b2

a3 b3

宽：a2-a1 高：b1

宽：a3-a2 高：b1+b2

宽：E - a3 高：b1+b2+b3

代码
let n = Number(readLine());
let e = Number(readLine());
// let n = Number("2");
// let e = Number("4");
 
let list = [];
 
for(let i=0; i<n; i++){
    let ints = [];
    ints[0] = Number(readLine());
    ints[1] = Number(readLine());
    list.push(ints);
}
 
//let list = [[0,1],[2,-2]];
 
let res = 0;
let high = 0;
 
for(let i=1; i<list.length; i++){
    high += list[i-1][1];   //Y轴方向的运动轨迹(相当于高)
    res += Math.abs((list[i][0]-list[i-1][0])*high);
}
 
res += Math.abs((e - list[n-1][0])*(high + list[n-1][1]));
 
console.log(res);

--------------------------
标题： 贪吃蛇  | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
贪吃蛇是一个经典游戏，蛇的身体由若干方格连接而成，身体随蛇头移动。蛇头触碰到食物时，蛇的长度会增加一格。蛇头和身体的任一方格或者游戏版图边界碰撞时，游戏结束。
下面让我们来完成贪吃蛇游戏的模拟。给定一个N*M的数组arr，代表N*M个方格组成的版图，贪吃蛇每次移动一个方格。若arr[i][j] == 'H'，表示该方格为贪吃蛇的起始位置；若arr[i][j] == 'F'，表示该方格为食物，若arr[i][j] == 'E'，表示该方格为空格。

贪吃蛇初始长度为1，初始移动方向为向左。为给定一系列贪吃蛇的移动操作，返回操作后蛇的长度，如果在操作执行完之前已经游戏结束，返回游戏结束时蛇的长度。

贪吃蛇移动、吃食物和碰撞处理的细节见下面图示：



图1：截取了贪吃蛇移动的一个中间状态，H表示蛇头，F表示食物，数字为蛇身体各节的编号，蛇为向左移动，此时蛇头和食物已经相邻
图2：蛇头向左移动一格，蛇头和食物重叠，注意此时食物的格子成为了新的蛇头，第1节身体移动到蛇头位置，第2节身体移动到第1节身体位置，以此类推，最后添加第4节身体到原来第3节身体的位置。
图3：蛇头继续向左移动一格，身体的各节按上述规则移动，此时蛇头已经和边界相邻，但还未碰撞。
图4：蛇头继续向左移动一格，此时蛇头已经超过边界，发生碰撞，游戏结束。
图5和图6给出一个蛇头和身体碰撞的例子，蛇为向上移动。图5时蛇头和第7节身体相邻，但还未碰撞；图6蛇头向上移动一格，此时蛇头和第8节身体都移动到了原来第7节身体的位置，发生碰撞，游戏结束。

输入描述:

输入第一行为空格分隔的字母，代表贪吃蛇的移动操作。字母取值为U、D、L、R和G，U、D、L、R分别表示贪吃蛇往上、下、左、右转向，转向时贪吃蛇不移动，G表示贪吃蛇按当前的方向移动一格。用例保证输入的操作正确。第二行为空格分隔的两个数，指定N和M，为数组的行和列数。余下N行每行是空格分隔的M个字母。字母取值为H、F和E，H表示贪吃蛇的起始位置，F表示食物，E表示该方格为空。用例保证有且只有一个H，而F和E会有多个。

输出描述:

输出一个数字，为蛇的长度。

示例1
输入

D G G

3 3

F F F

F F H

E F E

输出

1

说明

贪吃蛇一开始就向下转向并且移动两步，此时蛇头已经和边界碰撞，游戏结束，蛇没有吃任何食物，故长度为1

示例2
输入

G G G

3 3

F F F

F F H

E F E

输出

3

说明

贪吃蛇保存最初的向左方向移动三步，此时蛇头已经和边界碰撞，游戏结束，蛇吃了两个食物，故长度为3

解题思路
1、游戏面板可以格式化为二维数组

2、将蛇的头部和身体分开，头部为一个包含x，y坐标的数组，身体为包含多个数组的集合。

3、蛇的前行：头部的x，y坐标的变更，向上：x-1；向下：x+1；向左：y-1；向右：y+1。身体部分：集合最前面加上之前头部数组，没有迟到食物则直接取出最后一个数组；碰到食物则不需要取出数组，但要记得将F置为E，防止后面再次走到此位置

代码
let action = readLine().split(" ");
let str = readLine().split(" ").map(i=>parseInt(i));
// let action = "G G G D G G R G U G G".split(" ");
// let str = "3 4".split(" ").map(i=>parseInt(i));
// let test = ["F F F H","F F F F","F E F F"];
 
var row = str[0];  //游戏面板宽度
var col = str[1];  //游戏面板长度
var panel = []; //游戏面板
let step = action.length;
var direction = "left"; //移动方向，初始方向为左
var snake = [];  //蛇的身体
var header = [];    //头部
var over = false; //撞墙游戏结束
 
for(let i=0;i<row;i++){
    let temp = readLine().split(" ");
    //let temp = test[i].split(" ");
    panel[i] = [];
    for(let j=0;j<col;j++){
        panel[i][j] = temp[j];
        if(temp[j] == "H"){    //头部位置
            header[0] = i;
            header[1] = j;
        }
    }
}
 
for(let i=0; i<step; i++){
    if(action[i] == "U"){
        direction = "up";
    }else if(action[i] == "D"){
        direction = "down";
    }else if(action[i] == "L"){
        direction = "left";
    }else if(action[i] == "R"){
        direction = "right";
    }else if(action[i] == "G"){
        move();
    }
    if(over){
        break;
    }
}
 
console.log(snake.length+1);
 
function move(){
 
    let x = header[0];
    let y = header[1];
    snake.unshift([x,y]);
 
    if(direction == "up"){
        if(x==0){
            over = true;
            return; //已经到边界，向上越界
        }
        header[0] = x-1;
        if(panel[x-1][y] == "F"){
            panel[x-1][y] = "E";
        }else if(snake.length!=0){
            snake.pop();
        }
    }else if(direction == "down"){
        if(x==row-1){
            over = true;
            return; //已经到边界，向下越界
        }
        header[0] = x+1;
        if(panel[x+1][y] == "F"){
            panel[x+1][y] = "E";
        }else if(snake.length != 0){
            snake.pop();
        }
    }else if(direction == "left"){
        if(y==0){
            over = true;
            return; //已经到边界，向左越界
        }
        header[1] = y-1;
        if(panel[x][y-1] == "F"){
            panel[x][y-1] = "E";
        }else if(snake.length != 0){
            snake.pop();
        }
    }else if(direction == "right"){
        if(y==col-1){
            over = true;
            return; //已经到边界，向右越界
        }
        header[1] = y+1;
        if(panel[x][y+1] == "F"){
            panel[x][y+1] = "E";
        }else if(snake.length != 0){
            snake.pop();
        }
    }
 
    snake.forEach(v=>{
        if(String(v) == String(header)){    //发生碰撞
            over = true;
            return;
        }
    });
}

--------------------------
标题：路灯照明问题 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
在一条笔直的公路上安装了N个路灯，从位置0开始安装，路灯之间间距固定为100米。
每个路灯都有自己的照明半径，请计算第一个路灯和最后一个路灯之间，无法照明的区间的长度和。

输入描述:

第一行为一个数N，表示路灯个数，1<=N<=100000
第二行为N个空格分隔的数，表示路径的照明半径，1<=照明半径<=100000*100

输出描述:

第一个路灯和最后一个路灯之间，无法照明的区间的长度和

示例1
输入

2

50 50

输出

0

说明

路灯1覆盖0-50，路灯2覆盖50-100，路灯1和路灯2之间(0米-100米)无未覆盖的区间

示例2
输入

4

50 70 20 70

输出

20

说明

[170,180],[220,230]，两个未覆盖的区间，总里程为20

解题思路
只要将两个相邻路灯的照明半径值进行相加，再跟100进行比较，大于100的说明可以覆盖照明，小于100的计算出的差值就是无法照明的区间长度

代码
let n = Number(readLine());
let ints = readLine().split(" ").map(i=>parseInt(i));
// let n = Number("4");
// let ints = "50 70 200 70".split(" ").map(i=>parseInt(i));
 
var list = [];
let res = 0;
let end = ints[0]; //第一个路灯照射范围的右边界
for(let i=1;i<ints.length;i++){
    let star = 100*i - ints[i]; //第i个路灯照射范围的左边界
    star = star<0 ? 0 : star;   //如果照射范围过大，start可能出现负数
    if(star>end){   //表示有没有照射的区域
        let unLight = [];
        unLight[0] = end;
        unLight[1] = star;
        list.push(unLight);
    }else if(list.length!=0 && star<list[list.length-1][1]){   //如果存在未照明区间且当前照射范围左边界大于最后一个未照射区间右边界
        updateList(star);
    }
    let indexEnd = 100*i + ints[i];  //第i个路灯照射范围的右边界
    end = end >= indexEnd ? end : indexEnd; //记录最远的照射右边界
}
 
for(let i=0;i<list.length;i++){
    res+= list[i][1]-list[i][0];
}
 
console.log(res);
 
function updateList(start){
 
    let isEnd = false;
 
    while (list.length>0 && !isEnd){
 
        let index = list.length-1;  //只跟最后一个未照明区间比较
        let unLightStart = list[index][0];  //未照射左边界
        let unLightEnd = list[index][1];    //为照射右边界
 
        if(start<=unLightStart){
            list.splice(index,1); //当前照射左边界小于等于未照射区间左边界，则此区间被照射，移除
        }else if(start<unLightEnd){
            list.splice(index,i);
            let unLight = [];
            unLight[0] = unLightStart;
            unLight[1] = start;
            list.push(unLight);  //如果照射左边界大于未照射区间左边界但小于右边界，则边界更新，且退出循环
            isEnd = true;
        }else {
            isEnd = true;   //上面两个都不符合则直接退出
        }
    }
}

--------------------------
标题：跳格子游戏 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
地上共有N个格子，你需要跳完地上所有的格子，但是格子间是有强 依赖关系 的，跳完前一个格子后，后续的格子才会被开启，格子间的依赖关系由多组steps数组给出，steps[0]表示前一个格子,steps[1]表示steps[0]可以开启的格子:

比如[0,1]表示从跳完第0个格子以后第1个格子就开启了，比如[2,1]，[2,3]表示跳完第2个格子后第1个格子和第3个格子就被开启了

请你计算是否能由给出的steps 数组 跳完所有的格子,如果可以输出yes，否则输出no

说明：

1.你可以从一个格子跳到任意一个开启的格子

2.没有前置依赖条件的格子默认就是开启的

3.如果总数是N，则所有的格子编号为[0,1,2,3....N-1]连续的数组

输入描述:

输入一个整数N表示总共有多少个格子，接着输入多组二维数组steps表示所有格子之间的依赖关系

输出描述:

如果能按照steps给定的依赖顺序跳完所有的格子输出yes

否则输出no

示例1
输入

3

0 1

0 2

输出

yes

说明

总共有三个格子[0,1,2]，跳完0个格子后第1个格子就开启了，跳到第0个格子后第2个格子也被开启了，按照0->1->2或者0->2->1的顺序都可以跳完所有的格子

示例2
输入

2

1 0

0 1

输出

no

说明

总共有2个格子，第1个格子可以开启第0格子，但是第1个格子又需要第0个格子才能开启，相互依赖，因此无法完成

示例3
输入

6

0 1

0 2

0 3

0 4

0 5

输出

yes

说明

总共有6个格子，第0个格子可以开启第1,2,3,4,5个格子，所以跳完第0个格子之后其他格子都被开启了，之后按任何顺序可以跳完剩余的格子

示例4
输入

5

4 3

0 4

2 1

3 2

输出

yes

说明

跳完第0个格子可以开启格子4，跳完格子4可以开启格子3，跳完格子3可以开启格子2，跳完格子2可以开启格子1，按照0->4->3->2->1这样就跳完所有的格子

示例5
输入

4

1 2

1 0

输出

yes

说明

总共4个格子[0,1,2,3]，格子1和格子3没有前置条件所以默认开启，格子1可以开启格子0和格子2，所以跳到格子1之后就可以开启所有的格子，因此可以跳完所有格子

备注:
1 <= N <500

steps[i].length=2

0<=step[i][0]，step[i][1]<N

解题思路
例如：依赖键值对为 {4,3}{0,4}{2,1}{3,2}{2,0}
 遍历所有的键值对
 例：
   从第一个{4,3}开始
   {4,3}->{3,2}  {4,3,2}
       ┊
       --{4,3,2}->{2,1}  {4,3,2,1}
       ┊
       --{4,3,2}->{2,0} {4,3,2,0}
           ┊
           --{4,3,2,0}->{0,4}  {4,3,2,0}中包含4产生闭环，返回false

代码
let n = Number(readLine());
//let n = Number("2");
//let test = ["1 0","0 1"];
 
let list = []
 
while (readLine()){
    list.push(readLine().split(" ").map(Number));
}
// for(let i=0;i<test.length;i++){
//     list.push(test[i].split(" ").map(Number));
// }
 
let isTrue = true;
let len = list.length;  //依赖关系的键值对长度
 
for (let i=0;i<len;i++){
    if(isBH(list[i])){
        isTrue = false;
        break;
    }
}
 
console.log(isTrue ? "yes" : "no");
 
/**
 * {4,3}{0,4}{2,1}{3,2}{2,0}
 * 遍历所有的键值对
 *例：
 *  从第一个{4,3}开始
 *  {4,3}->{3,2}  {4,3,2}
 *      ┊
 *      --{4,3,2}->{2,1}  {4,3,2,1}
 *      ┊
 *      --{4,3,2}->{2,0} {4,3,2,0}
 *          ┊
 *          --{4,3,2,0}->{0,4}  {4,3,2,0}中包含4产生闭环，返回false
 */
function isBH( listC){
 
    for(let i=0; i<list.length; i++){
 
        let temp = list[i];
        if(temp[0] == listC[listC.length-1]){
            if(listC.includes(temp[1])){
                return true;
            }
            listC.push(temp[1]);
            isBH(listC);
        }
    }
 
    return false;
}

--------------------------
标题：转骰子 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
骰子是一个立方体，每个面一个数字，初始为左1，右2，前3（观察者方向），后4，上5，下6，用123456表示这个状态，放置到平面上，可以向左翻转（用L表示向左翻转1次），可以向右翻转（用R表示向右翻转1次），可以向前翻转（用F表示向前翻转1次），可以向后翻转（用B表示向后翻转1次），可以逆时针旋转（用A表示逆时针旋转90度），可以顺时针旋转（用C表示顺时针旋转90度），现从123456这个初始状态开始，根据输入的动作序列，计算得到最终的状态。

骰子的初始状态和初始状态转动后的状态如图所示



输入描述:

输入一行，为只包含LRFBAC的字母序列，最大长度50，字母可重复

输出描述:

输出最终状态

示例1
输入

LR

输出

123456

说明

骰子先向左翻转，再向右翻转回来，故还是原来的状态123456

示例2
输入

FCR

输出

342156

说明

骰子向前翻转，状态变为125643，再顺时针旋转，状态变为651243，最后向右翻转，状态变为342156

解题思路
将转向各个方向的排序列出，然后对输入值进行遍历，求出骰子最终状态

代码
let s = readLine();
//let s = "FCR";
 
let res = "123456";  //骰子的初始状态
 
for(let i=0;i<s.length;i++){
    res = zhuanSZ(s.charAt(i),res);
}
 
console.log(res);
 
function zhuanSZ(s, sz){
 
    let s1 = sz.charAt(0);
    let s2 = sz.charAt(1);
    let s3 = sz.charAt(2);
    let s4 = sz.charAt(3);
    let s5 = sz.charAt(4);
    let s6 = sz.charAt(5);
 
    /**
     * 骰子转向各个方向的重新排序
     */
    switch (s){
        case "L":
            return s5+s6+s3+s4+s2+s1;
        case "R":
            return s6+s5+s3+s4+s1+s2;
        case "F":
            return s1+s2+s5+s6+s4+s3;
        case "B":
            return s1+s2+s6+s5+s3+s4;
        case "A":
            return s4+s3+s1+s2+s5+s6;
        case "C":
            return s3+s4+s2+s1+s5+s6;
    }
    return "";
}

--------------------------
标题：连续出牌数量 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
有这么一款单人卡牌游戏，牌面由颜色和数字组成，颜色为红、黄、蓝、绿中的一种，数字为0-9中的一个。游戏开始时玩家从手牌中选取一张卡牌打出，接下来如果玩家手中有和他上一次打出的手牌颜色或者数字相同的手牌，他可以继续将该手牌打出，直至手牌打光或者没有符合条件可以继续打出的手牌。
现给定一副手牌，请找到最优的出牌策略，使打出的手牌最多。

输入描述:

输入为两行，第一行是每张手牌的数字，数字由空格分隔，第二张为对应的每张手牌的颜色，用r y b g这4个字母分别代表4种颜色，字母也由空格分隔。手牌数量不超过10。

输出描述:

输出一个数字，即最多能打出的手牌的数量。

示例1
输入

1 4 3 4 5

r y b b r

输出

3

说明

如果打出1r，那么下面只能再打出5r，共打出两张牌，而按照4y-4b-3b的顺序则可以打出三张牌，故输出3

示例2
输入

1 2 3 4

r y b l

输出

1

说明

没有能够连续出牌的组合，只能在开始时打出一张手牌，故输出1

解题思路
看到这种需要轮循遍历的场景就要想到 递归

1、将输入的牌作为数组（[数字，颜色]）放入集合中

2、 遍历集合 ，循环取出其中一张牌

3、将取出的这张牌与其他牌进行比较，如果出现数字相同或者颜色相同的牌，就将其取出，重

      复步骤3，直至遍历到最后一张牌也没有符合条件的为止（递归边界）。

       注意： 每取出一张牌，都需要从集合中剔除此牌，且出牌次数需要加一。

此题最要注意的就是， 每次递归的时候，都需要复制一次集合 ，防止出牌的时候影响之后的手牌。

代码
let str1 = readLine().split(" ");
let str2 = readLine().split(" ");
//let str1 = "1 4 3 4 5".split(" ");
//let str2 = "r y b b r".split(" ");
//let str1 = "1 2 3 4".split(" ");
//let str2 = "r y b l".split(" ");
 
let list = [];    //卡牌集合
let len = str1.length;  //卡牌数量
var max = 0;
 
for(let i=0;i<len;i++){
    let strings = [];
    strings[0] = str1[i];
    strings[1] = str2[i];
    list.push(strings);  //将每张卡牌的数字和颜色作为数组放入集合中
}
 
for(let i=0;i<len;i++){
    let copyList = copy(list);   //需要备份集合，集合内容会受到上次的操作影响
    copyList.splice(i, 1); //将索引为i的牌取出
    chupai(list[i], copyList, 1);   //出牌数量count，初始化为1
}
 
console.log(max);
    
function copy( list){
 
    let len = list.length;
    let res = [];
 
    for(let i=0;i<len;i++){
        res.push(list[i]);
    }
 
    return res;
}
 
/**
 *
 * @param str   此时用来做对比的牌
 * @param list  此时手上的牌（除去出过的牌）
 * @param count 出牌次数
 */
function chupai( str, list, count){
 
    for(let i=0; i<list.length; i++){
 
        let strings = list[i];
 
        if(strings[0] == str[0] || strings[1] == str[1]){ //如果数字相同或者颜色相同则进入下轮出牌
 
            let temp = copy(list);
            temp.splice(i, 1);
 
            if(temp.length == 0){ //手上的牌出完了
                max = Math.max(max, count+1);
                break;
            }
 
            chupai(strings, temp, count+1);
        }else if(i == list.length-1){ //遍历到最后一张都没有可以出的牌
 
            max = Math.max(max, count);
        }
 
    }
 
}

--------------------------
标题：连续字母长度 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
给定一个字符串，只包含大写字母，求在包含同一字母的子串中，长度第 k 长的子串的长度，相同字母只取最长的那个子串。

输入描述:

第一行有一个子串(1<长度<=100)，只包含大写字母。

第二行为 k的值

输出描述:

输出连续出现次数第k多的字母的次数。

示例1
输入

AAAAHHHBBCDHHHH

3

输出

2

说明

同一字母连续出现的最多的是A和H，四次；第二多的是H，3次，但是H已经存在4个连续的，故不考虑；下个最长子串是BB，所以最终答案应该输出2。

示例2
输入

AABAAA

2

输出

1

说明

同一字母连续出现的最多的是A，三次；第二多的还是A，两次，但A已经存在最大连续次数三次，故不考虑；下个最长子串是B，所以输出1

示例3
输入

ABC

4

输出

-1

说明

只含有3个包含同一字母的子串，小于k，输出-1

示例4
输入

ABC

2

输出

1

说明

三个子串长度均为1，所以此时k = 1，k=2，k=3这三种情况均输出1。特此说明，避免歧义。

备注:

若子串中只包含同一字母的子串数小于k，则输出-1

解题思路
遍历字符串 根据次数放入map键值对中，key：字符串，value：连续出现次数；

对value值进行降序排序

代码
let s = readLine();
let n = Number(readLine());
// let s = "AABAAA";
// let n = Number("2");
 
let map = {};
let count = 1;    //相同字符的个数
for(let i=0;i<s.length-1;i++){
    if(s.charAt(i)==s.charAt(i+1)){ //当前字符跟后面一个字符比较，所以边界为s.length()-1
        count++;   //相同字符计数加1
    } else {
        if(map[s.charAt(i)]){
            count = Math.max(count,map[s.charAt(i)]);    //同字符长度取最长长度
        }
        map[s.charAt(i)] = count;
        count = 1;
    }
    if(i==s.length-2){    //最后一个字符
        let key = count==1 ? s.charAt(i+1) : s.charAt(i);
        map[key] = Math.max(map[key], count);
    }
}
 
let list = [];    //长度（value）集合
 
for (let c in map
        ) {
    list.push(map[c]);
}
 
list.sort((a,b)=>{    //根据长度降序处理
    if (b>a){
        return 1;
    }
    return -1;
});
 
if(list.length>=n){
    console.log(list[n-1]);
}else {
    console.log(-1);
}

--------------------------
标题：非严格递增连续数字序列 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
输入一个 字符串 仅包含大小写字母和数字，求字符串中包含的最长的非严格递增连续数字序列的长度（比如12234属于非严格递增连续数字序列）。

输入描述:

输入一个字符串仅包含大小写字母和数字，输入的字符串最大不超过255个字符。

输出描述:

最长的非严格递增连续数字序列的长度

示例1
输入

abc2234019A334bc

输出

4

说明

2234为最长的非严格递增连续数字序列，所以长度为4。

代码
//let s = readline();
let s = "abc2234019A334bc";
 
let n = s.length;
let max = 0;    //最大长度
let count = 0;    //符合条件的数字长度
let numReg = new RegExp("^[0-9]{1}$");
 
if(numReg.test(s.charAt(0))){ //如果第一个字符为数字则将count置1
    count=1;
}
 
for(let i=1; i<n; i++){
    if(numReg.test(s.charAt(i))){ //判断字符是否为数字
        if(count!=0 ){  //count不为0则可以进行比较，反则置为1，下次进行比较
            if((s.charAt(i)>=s.charAt(i-1))){   //符合条件
                count++;
            }else {
                max = Math.max(max,count);  //不符合条件则抛出最大
                count = 1;  //因为为数字，所以置1
            }
        }else {
            count=1;
        }
    }else if(count!=0){
        max = Math.max(max,count);
        count = 0;
    }
}
 
console.log(max);

--------------------------
标题：靠谱的车 | 时间限制：1秒 | 内存限制：262144K | 语言限制：不限
程序员小明打了一辆出租车去上班。出于职业敏感，他注意到这辆出租车的计费表有点问题，总是偏大。

出租车司机解释说他不喜欢数字4，所以改装了计费表，任何数字位置遇到数字4就直接跳过，其余功能都正常。

比如：

1.     23再多一块钱就变为25；

2.     39再多一块钱变为50；

3.     399再多一块钱变为500；

小明识破了司机的伎俩，准备利用自己的学识打败司机的阴谋。

给出计费表的表面读数，返回实际产生的费用。

输入描述:

只有一行，数字N，表示里程表的读数。

(1<=N<=888888888)。

输出描述:

一个数字，表示实际产生的费用。以回车结束。

示例1
输入

5

输出

4

说明

5表示计费表的表面读数。

4表示实际产生的费用其实只有4块钱。

示例2
输入

17

输出

15

说明

17表示计费表的表面读数。

15表示实际产生的费用其实只有15块钱。

示例3
输入

100

输出

81

说明

100表示计费表的表面读数。

81表示实际产生的费用其实只有81块钱。

解题思路
初始化j = 1：j表示以4开头的个数，个位数4开头1（4）个，两位数4开头10（40-49）个，三位数4开头100（400-499）个。。。呈指数级增长

初始化k=0：k表示进制内的含4个数，如10以内含4为1（k*9+j->0*9+1），100以内含4为19（K*9+j->1*9+10），1000以内含4为271（k*9+j->19*9+100）。。。呈规律性增长

初始化temp为0，包含4的个数

如352：

1、先处理个位数，352除以10得35余2，2小于4，temp=0； k=1（k*9+j）； j=10(10*j)；

2、处理十位数，步骤1获得的35除以10得3余5，因为5>4，所以包含40-49，因此需要加上j（10）的值，步骤1所得k=1，j=10；temp=0（步骤1处理后的temp）+（5-1）*k+j=14；k=(k*9+j)=19； j=j*10=100

3、处理百位数，步骤2获得的3除以10得0余3，因为3<4，不需要加上j，

temp=14+3*k = 14+3*19 = 71;

最后得到：352-71 = 281

代码
let n = Number(readLine());
//let n = Number("100");
 
let ans = n;
let temp = 0;
let k=0;    //进制内含4的个数
let j=1;    //4开头的数字
 
while(n > 0){
    if(n%10 > 4){
        temp += (n%10-1)*k+j;
    }else{
        temp += (n%10)*k;
    }
    //进制数内的含4个数
    k = k*9+j;
    j*=10;
    n = Math.floor(n/10);
}
 
console.log(ans-temp);
